QTcpSocket двусторонняя связь клиент-сервер

Я разрабатываю приложение для Raspberry PI на основе интерфейса сокетов. Основная идея заключается в том, что Raspberry будет подключен к датчику, собирать данные и отправлять их через WiFi на устройство Android. С Android я могу общаться с датчиком, отправляя некоторые команды. Я новичок в этом виде разработки и, следуя некоторым учебникам по QTcpSocket, я создал простое клиент-серверное приложение, но оно только в одном направлении. Сервер прослушивает то, что отправляет клиент. Не могли бы вы помочь мне превратить это в двухстороннее общение? Я читал, что QTcpSocket не требует многопоточности для такого рода проблем, но я не нашел никакого решения.

Буду признателен за любую помощь!

server.cpp:

#include "server.h"#include <QTcpServer>
#include <QTcpSocket>
#include <cstdio>
#include <QtDebug>

Server::Server(QObject *parent) :
QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()),
this, SLOT(on_newConnection()));
}

void Server::listen()
{
server->listen(QHostAddress::Any, 5100);
}

void Server::on_newConnection()
{
socket = server->nextPendingConnection();

if(socket->state() == QTcpSocket::ConnectedState)
{
printf("New connection established.\n");
qDebug()<<socket->peerAddress();
}
connect(socket, SIGNAL(disconnected()),
this, SLOT(on_disconnected()));
connect(socket, SIGNAL(readyRead()),
this, SLOT(on_readyRead()));
}

void Server::on_readyRead()
{
while(socket->canReadLine())
{
QByteArray ba = socket->readLine();

if(strcmp(ba.constData(), "!exit\n") == 0)
{
socket->disconnectFromHost();
break;
}
printf(">> %s", ba.constData());
}
}

void Server::on_disconnected()
{
printf("Connection disconnected.\n");
disconnect(socket, SIGNAL(disconnected()));
disconnect(socket, SIGNAL(readyRead()));
socket->deleteLater();
}

client.cpp

#include "client.h"#include <QTcpSocket>
#include <QHostAddress>
#include <cstdio>

Client::Client(QObject *parent) : QObject(parent)
{
socket = new QTcpSocket(this);
printf("try to connect.\n");
connect(socket, SIGNAL(connected()),
this, SLOT(on_connected()));
}

void Client::on_connected()
{
printf("Connection established.\n");
char buffer[1024];
forever
{
while(socket->canReadLine())
{
QByteArray ba = socket->readLine();
printf("from server: %s", ba.constData());
}
printf(">> ");
gets(buffer);
int len = strlen(buffer);
buffer[len] = '\n';
buffer[len+1] = '\0';
socket->write(buffer);
socket->flush();
}

}

void Client::connectToServer()
{
socket->connectToHost(QHostAddress::LocalHost, 5100);
}

4

Решение

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

Затем просто читайте (записывайте) из (в) экземпляра QTCPSocket в соответствии с заданным потоком.

Вы можете, например, прочитать данные на стороне сервера, проверить, что вы должны ответить, и записать ответ в тот же сокет, из которого вы прочитали. Для сообщений, ориентированных на строки (и только для них), код может выглядеть так:

    void Server::on_readyRead()
{
// "while" loop would block until at least one whole line arrived
// I would use "if" instead
if(socket->canReadLine())
{
QByteArray ba = socket->readLine();

QByteArray response;

// some code which parses arrived message
// and prepares response

socket->write(response);
}
//else just wait for more data
}

Лично я бы переместил разбор и отправку ответов из слота on_readyRead (), чтобы избежать слишком длительного блокирования цикла событий, но, поскольку вы — новичок в сетевом программировании, я просто хотел уточнить, что можно сделать для реализации двусторонней связи.

Для более подробной информации вы можете увидеть http://qt-project.org/doc/qt-4.8/qtnetwork.html

Помните о проверке, все ли сообщения поступили как на стороне клиента, так и на стороне сервера. Если вы используете свой собственный протокол (не HTTP, FTP или другой стандартизированный), вы можете добавить длину сообщения в начале сообщения.

5

Другие решения

Все, что вам нужно сделать, это написать / прочитать из сокета с клиента или сервера. TCP-соединение — это уже двустороннее соединение.

У вас могут быть проблемы с вашим forever зациклиться Client, Вы должны действительно использовать readyRead сигнал на сокете так же, как вы делаете для сервера и сбросить forever петля.

Обрабатывайте ввод с клавиатуры неблокирующим образом, а не используя gets(), gets() заблокирует основной поток и предотвратит запуск цикла обработки событий. Это не лучший способ обработки вещей в вашем случае, так как вы хотите иметь возможность обрабатывать данные с сервера и от пользователя одновременно.

Может быть, взглянем на это в отношении обработки клавиатуры из консольного приложения:

используя-QTextStream для чтения-STDIN-в-неблокируемому-моды

Или сделайте приложение с графическим интерфейсом и используйте QPlainTextEdit,

1

По вопросам рекламы [email protected]