Сервис для
сео - оптимизаторов

Найди ошибки на сайте
Ошибки мешают продвижению сайта
Исправь ошибки на сайте
Сайт без ошибок продвигать легче
Получи новых клиентов
Новые клиенты принесут больше прибыль

Пример чата Bluetooth

  1. Запуск примера
  2. Чат-сервер
  3. Клиент чата
  4. Диалог чата

Пример, показывающий связь через Bluetooth.

Пример чата Bluetooth показывает, как использовать Qt Bluetooth API для связи с другим приложением на удаленном устройстве с помощью Bluetooth.

Пример чата Bluetooth реализует простую программу чата между несколькими участниками. Приложение всегда действует как сервер и клиент, устраняя необходимость определять, к кому следует подключаться.

Запуск примера

Чтобы запустить пример из Qt Creator откройте режим приветствия и выберите пример из примеров . Для получения дополнительной информации посетите Сборка и запуск примера ,

Чат-сервер

Сервер чата реализован классом ChatServer. Класс ChatServer объявлен как:

Первое, что нужно сделать серверу чата, - это создать экземпляр QRfcommServer для прослушивания входящих Bluetooth-соединений. Наш слот clientConnected () будет вызываться всякий раз, когда создается новое соединение.

rfcommServer = new QBluetoothServer ( QBluetoothServiceInfo :: RfcommProtocol, это); подключиться (rfcommServer, & QBluetoothServer :: newConnection, this, QOverload <> :: of (& ChatServer :: clientConnected)); bool result = rfcommServer -> listen (localAdapter); if (! result) { qWarning () <<"Невозможно привязать сервер чата к" <<localAdapter .toString (); вернуть ; }

Сервер чата полезен, только если другие знают, что он там есть. Чтобы другие устройства могли обнаружить его, запись, описывающая услугу, должна быть опубликована в базе данных системного протокола SDP (Service Discovery Protocol). QBluetoothServiceInfo класс инкапсулирует служебную запись.

Мы опубликуем запись службы, которая содержит некоторые текстурные описания служб, UUID, который однозначно идентифицирует службу, атрибут обнаруживаемости и параметры соединения.

Текстурное описание службы хранится в атрибутах ServiceName, ServiceDescription и ServiceProvider.

Bluetooth использует UUID в качестве уникальных идентификаторов. Служба чата использует случайно сгенерированный UUID.

static const QLatin1String serviceUuid ("e8e10f95-1a70-4b27-9ccf-02010264e9c8"); serviceInfo .setServiceUuid ( QBluetoothUuid (ServiceUuid));

Служба Bluetooth доступна только в том случае, если она находится в PublicBrowseGroup.

Атрибут ProtocolDescriptorList используется для публикации параметров подключения, которые требуется удаленному устройству для подключения к нашей службе. Здесь мы указываем, что используется протокол Rfcomm, и устанавливаем номер порта для порта, который прослушивает наш экземпляр rfcommServer.

Наконец, мы регистрируем служебную запись в системе.

serviceInfo .registerService (localAdapter);

Как упоминалось ранее, входящие соединения обрабатываются в слоте clientConnected (), где ожидающие соединения подключены к сигналам readyRead () и disconnected (). Сигналы уведомляют других о подключении нового клиента.

void ChatServer :: clientConnected () { QBluetoothSocket * socket = rfcommServer -> nextPendingConnection (); if (! socket) return; подключить (розетка, & QBluetoothSocket :: readyRead, this & & ChatServer :: readSocket); подключить (розетка, & QBluetoothSocket :: отключено, this, QOverload <> :: of (& ChatServer :: clientDisconnected)); clientSockets .append (сокет); emit clientConnected (socket -> peerName ()); }

Слот readSocket () вызывается всякий раз, когда данные готовы для чтения из клиентского сокета. Слот считывает отдельные строки из сокета, преобразует их из UTF-8 и испускает сигнал messageReceived ().

void ChatServer :: readSocket () { QBluetoothSocket * socket = qobject_cast < QBluetoothSocket *> (отправитель ()); if (! socket) return; while (socket -> canReadLine ()) { QByteArray line = socket -> readLine () .trimmed (); emit messageReceived (socket -> peerName (), QString :: fromUtf8 (line .constData (), line .length ())); }}

Слот clientDisconnected () вызывается всякий раз, когда клиент отключается от службы. Слот испускает сигнал, чтобы уведомить других о том, что клиент отключился, и удаляет сокет.

void ChatServer :: clientDisconnected () { QBluetoothSocket * socket = qobject_cast < QBluetoothSocket *> (отправитель ()); if (! socket) return; emit clientDisconnected (socket -> peerName ()); clientSockets .removeOne (сокет); сокет -> deleteLater (); }

Слот sendMessage () используется для отправки сообщения всем подключенным клиентам. Сообщение преобразуется в UTF-8 и добавляется с новой строкой перед отправкой всем клиентам.

Когда сервер чата остановлен, служебная запись удаляется из системной базы данных SDP, все подключенные клиентские сокеты удаляются, а экземпляр QRfcommServer удаляется.

void ChatServer :: stopServer () {serviceInfo .unregisterService (); qDeleteAll (clientSockets); удалить rfcommServer; rfcommServer = nullptr; }

Клиент чата

Клиент чата реализован классом ChatClient. Класс ChatClient объявлен как:

класс ChatClient: общедоступный QObject {Q_OBJECT public: явный ChatClient ( QObject * parent = nullptr); ~ ChatClient (); void startClient (const QBluetoothServiceInfo & remoteService); void stopClient (); открытые слоты: void sendMessage (const QString & сообщение); сигналы: void messageReceived (const QString & отправитель, const QString & сообщение); пустота соединена QString & название); void отключен (); void socketErrorOccurred (const QString & errorString); закрытые слоты: void readSocket (); void подключен (); void onSocketErrorOccurred ( QBluetoothSocket :: Ошибка сокета); частный : QBluetoothSocket * socket = nullptr; };

Клиент создает новый QBluetoothSocket и подключается к удаленному сервису, описанному параметром remoteService . Слоты подключаются к сокетам сигналов readyRead (), connected () и disconnected ().

void ChatClient :: startClient (const QBluetoothServiceInfo & remoteService) {if (socket) return; сокет = новый QBluetoothSocket ( QBluetoothServiceInfo :: RfcommProtocol); QDebug () <<"Создать сокет"; сокет -> connectToService (remoteService); QDebug () <<"ConnectToService done"; подключить (розетка, & QBluetoothSocket :: readyRead, this & & ChatClient :: readSocket); подключить (розетка, & QBluetoothSocket :: connected, this, QOverload <> :: of (& ChatClient :: connected)); подключить (розетка, & QBluetoothSocket :: отключено, это & ​​ChatClient :: отключено); подключиться (сокет, QOverload < QBluetoothSocket :: SocketError> :: of (& QBluetoothSocket :: error), это & ​​ChatClient :: onSocketErrorOccurred); }

При успешном подключении к сокету мы издаем сигнал для уведомления других.

void ChatClient :: connected () {emit connected (socket -> peerName ()); }

Подобно серверу чата, слот readSocket () вызывается, когда данные доступны из сокета. Строки читаются индивидуально и конвертируются из UTF-8. Сигнал messageReceived () испускается.

void ChatClient :: readSocket () {if (! socket) return; while (socket -> canReadLine ()) { QByteArray line = socket -> readLine (); emit messageReceived (socket -> peerName (), QString :: fromUtf8 (line .constData (), line .length ())); }}

Слот sendMessage () используется для отправки сообщения на удаленное устройство. Сообщение преобразуется в UTF-8, и добавляется новая строка.

void ChatClient :: sendMessage (const QString & сообщение) { QByteArray текст = сообщение .toUtf8 () + '\ n'; сокет -> написать (текст); }

Чтобы отключиться от удаленного чата, QBluetoothSocket Экземпляр удален.

void ChatClient :: stopClient () {удалить сокет; сокет = nullptr; }

Диалог чата

Главное окно этого примера - диалог чата, реализованный в классе Chat. Этот класс отображает сеанс чата между одним ChatServer и нулем или более ChatClients. Класс Chat объявлен как:

класс Chat: public QDialog {Q_OBJECT public: явный Chat (QWidget * parent = nullptr); ~ Чат (); сигналы: void sendMessage (const QString & сообщение); приватные слоты: void connectClicked (); void sendClicked (); void showMessage (const QString & отправитель, const QString & сообщение); void clientConnected (const QString & название); void clientDisconnected (const QString & название); void clientDisconnected (); пустота соединена QString & название); void ReactionOnSocketError (const QString & ошибка); void newAdapterSelected (); private: int adapterFromUserSelection () const; int currentAdapterIndex = 0; Ui_Chat * ui; ChatServer * сервер; QList <ChatClient *> клиенты; QList < QBluetoothHostInfo > локальные адаптеры; QString LocalName; };

Сначала мы создаем пользовательский интерфейс

ui -> setupUi (это); connect (ui -> quitButton, & QPushButton :: clicked, this, & Chat :: accept); connect (ui -> connectButton, & QPushButton :: clicked, this, & Chat :: connectClicked); connect (ui -> sendButton, & QPushButton :: clicked, this, & Chat :: sendClicked);

Мы создаем экземпляр ChatServer и отвечаем на его сигналы clientConnected (), clientDiconnected () и messageReceived ().

сервер = новый ChatServer (это); подключиться (сервер, QOverload <const QString &> :: of (& ChatServer :: clientConnected), это, & Chat :: clientConnected); подключиться (сервер, QOverload <const QString &> :: of (& ChatServer :: clientDisconnected), это, QOverload <const QString &> :: of (& Chat :: clientDisconnected)); connect (сервер, & ChatServer :: messageReceived, this, & Chat :: showMessage); подключиться (это & ​​Chat :: sendMessage, сервер & ChatServer :: sendMessage); сервер -> startServer ();

В ответ на сигналы clientSnever () и clientDisconnected () ChatServer мы отображаем типичный «X присоединился к чату». и "Ушел". сообщения в чате.

void Chat :: clientConnected (const QString & name) {ui -> chat -> insertPlainText ( QString :: fromLatin1 ("% 1 присоединился к чату. \ n"). Arg (имя)); } void Chat :: clientDisconnected (const QString & name) {ui -> chat -> insertPlainText ( QString :: fromLatin1 ("% 1 покинул. \ n"). Arg (имя)); }

Входящие сообщения от клиентов, подключенных к ChatServer, обрабатываются в слоте showMessage (). Текст сообщения, помеченный именем удаленного устройства, отображается в сеансе чата.

void Chat :: showMessage (const QString & отправитель, const QString & message) {ui -> chat -> insertPlainText ( QString :: fromLatin1 ("% 1:% 2 \ n"). arg (отправитель, сообщение)); пользовательский интерфейс -> чат -> sureCursorVisible (); }

В ответ на нажатие кнопки подключения приложение запускает обнаружение служб и представляет список обнаруженных служб чата на удаленных устройствах. ChatClient для сервиса выбирается пользователем.

void Chat :: connectClicked () {ui -> connectButton -> setEnabled (false); Const QBluetoothAddress адаптер = localAdapters .isEmpty ()? QBluetoothAddress (): localAdapters .at (currentAdapterIndex) .address (); RemoteSelector remoteSelector (адаптер); #ifdef Q_OS_ANDROID if (QtAndroid :: androidSdkVersion ()> = 23) remoteSelector .startDiscovery ( QBluetoothUuid (ReverseUuid)); иначе remoteSelector .startDiscovery ( QBluetoothUuid (ServiceUuid)); #else remoteSelector .startDiscovery ( QBluetoothUuid (ServiceUuid)); #endif if (remoteSelector .exec () = = QDialog :: Accepted) { QBluetoothServiceInfo service = remoteSelector .service (); QDebug () <<"Подключение к услуге 2" <<service .serviceName () <<"on" <<service .device () .name (); QDebug () <<"Собираюсь создать клиента"; ChatClient * client = новый ChatClient (это); QDebug () <<"Подключение ..."; connect (клиент, & ChatClient :: messageReceived, this, & Chat :: showMessage); connect (клиент, & ChatClient :: отключен, this, QOverload <> :: of (& Chat :: clientDisconnected)); подключиться (клиент, QOverload <const QString &> :: of (& ChatClient :: connected), это, & Chat :: connected); connect (client, & ChatClient :: socketErrorOccurred, this, & Chat :: ReactionOnSocketError); connect (this, & Chat :: sendMessage, client, & ChatClient :: sendMessage); QDebug () <<«Запустить клиент»; клиент -> startClient (сервис); клиенты .append (клиент); } ui -> connectButton -> setEnabled (true); }

В ответ на сигналы connected () от ChatClient мы отображаем «Присоединенный чат с X». сообщение в чате.

void Chat :: connected (const QString & name) {ui -> chat -> insertPlainText ( QString :: fromLatin1 ("Присоединен к чату с% 1. \ n"). Arg (имя)); }

Сообщения отправляются на все удаленные устройства через экземпляры ChatServer и ChatClient с помощью сигнала sendMessage ().

void Chat :: sendClicked () {ui -> sendButton -> setEnabled (false); ui -> sendText -> setEnabled (false); showMessage (localName, ui -> sendText -> text ()); emit sendMessage (ui -> sendText -> text ()); ui -> sendText -> clear (); ui -> sendText -> setEnabled (true); ui -> sendButton -> setEnabled (true); }

Нам нужно очистить экземпляры ChatClient, когда удаленное устройство вызывает отключение.

void Chat :: clientDisconnected () {ChatClient * client = qobject_cast <ChatClient *> (sender ()); if (клиент) {клиенты .removeOne (клиент); клиент -> deleteLater (); }}

файлы:

IsEmpty ()?