Двунаправленный клиентский сервер Qt с использованием QTcpSocket и QTcpServer - PullRequest
10 голосов
/ 19 января 2012

Я пытаюсь реализовать двунаправленную программу клиент-сервер, где клиенты и серверы могут передавать сериализованные объекты между собой. Я пытаюсь сделать это с помощью Qt (QTcpSocket и QTcpServer). Я реализовал такие программы в Java, но я не могу понять, как это сделать с помощью Qt. Я проверил примеры клиента состояния и сервера состояния ... но, насколько я вижу, клиент просто сигнализирует серверу, а сервер отправляет ему некоторые данные. Мне нужно, чтобы клиент и сервер отправляли объекты туда и обратно. Я не ищу полного решения, все, что я ищу, - это какое-то руководство в правильном направлении.

Я написал некоторый код, который принимает соединение, но не принимает данные.

SERVER

этот класс является сервером; он должен принимать соединение и выводить размер буфера, который отправляется. Однако он выводит 0

#include "comms.h"

Comms::Comms(QString hostIP, quint16 hostPort)
{
    server = new QTcpServer(this);
    hostAddress.setAddress(hostIP);
    this->hostPort = hostPort;


}

void Comms::attemptConnection(){
    connect(server, SIGNAL(newConnection()), this, SLOT(connectionAccepted()));
    //socket = server->nextPendingConnection();
    server->listen(hostAddress,hostPort);
    //receivedData = socket->readAll();
}

void Comms::connectionAccepted(){
    qDebug()<<"Connected";
    socket = new QTcpSocket(server->nextPendingConnection());

    char* rec = new char[socket->readBufferSize()];
    qDebug()<<socket->readBufferSize();
}

КЛИЕНТ

Этот класс является клиентом. Это должно быть отправка строки «привет». Успешно отправляет (насколько мне известно)

#include "toplevelcomms.h"
#include "stdio.h"

TopLevelComms::TopLevelComms(QString hostIP, quint16 hostPort)
{
    tcpSocket = new QTcpSocket();
    hostAddress.setAddress(hostIP);
    this->hostPort = hostPort;
}


void TopLevelComms::connect(){
    tcpSocket->connectToHost(hostAddress,hostPort,QIODevice::ReadWrite);
    //tcpSocket->waitForConnected(1);

    QString string = "Hello";
    QByteArray array;
    array.append(string);
    qDebug()<<tcpSocket->write(array);
}

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

Ответы [ 2 ]

10 голосов
/ 19 января 2012

QTcpSocket по умолчанию асинхронный, поэтому, когда вы вызываете connectToHost и пишете в том же контексте, он не будет отправлен, так как сокет не подключен.Вы должны изменить свой «клиентский» код:

void TopLevelComms::connect(){
    tcpSocket->connectToHost(hostAddress,hostPort,QIODevice::ReadWrite);
    if(tcpSocket->waitForConnected()) // putting 1 as parameter isn't reasonable, using default 3000ms value
    {
        QString string = "Hello";
        QByteArray array;
        array.append(string);
        qDebug()<<tcpSocket->write(array);
    }
    else
    {
        qDebug() << "couldn't connect";
    }
}

Примечание: вы также не проверяли, можете ли вы слушать

void Comms::attemptConnection(){
    connect(server, SIGNAL(newConnection()), this, SLOT(connectionAccepted()));
    //socket = server->nextPendingConnection();

    if(server->listen(hostAddress,hostPort))
    {
        qDebug() << "Server listening";
    }
    else
    {
        qDebug() << "Couldn't listen to port" << server->serverPort() << ":" << server->errorString();
    }
    //receivedData = socket->readAll();
}

И последнее.Обратите внимание, что QTcpServer :: nextPendingConnection () возвращает QTcpSocket, поэтому вместо того, чтобы брать это новое соединение, вы создаете новый QTcpSocket с nextPendingConnection в качестве родительского

void Comms::connectionAccepted(){
    qDebug()<<"Connected";
    // WRONG! it will use QTcpSocket::QTcpSocket(QObject * parent)
    //socket = new QTcpSocket(server->nextPendingConnection());
    // use simple asign
    socket = server->nextPendingConnection();
    // move reading to slot
    connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket()));
}

, теперь мы переместим чтение в отдельный слот

void Comms::readSocket()
{
    // note that dynamic size array is incompatible with some compilers
    // we will use Qt data structure for that
    //char* rec = new char[socket->readBufferSize()];
    qDebug()<<socket->readBufferSize();
    // note that QByteArray can be casted to char * and const char *
    QByteArray data = socket->readAll();
}

Должен признать, что ошибок много, как для такого небольшого примера кода.Вы должны получить некоторые знания о соединениях TCP / IP.Это потоки, и нет никакой гарантии, что весь блок данных попадет к вам сразу

5 голосов
/ 19 января 2012

Похоже, у вас проблема с синхронизацией. Поскольку ваш клиент и сервер - это разные процессы, вы никак не можете гарантировать, что все TopLevelComms::connect() будет выполнено (вместе с передачей сетевых данных) до того, как функция connectionAccepted() вашего сервера попытается выполнить чтение из сокета.

Я подозреваю, что если вы воспользуетесь функцией waitForReadyRead () QTcpSocket, вам повезет больше:

void Comms::connectionAccepted(){
    qDebug()<<"Connected";
    socket = new QTcpSocket(server->nextPendingConnection());

    if( socket->waitForReadyRead() ) {
        char* rec = new char[socket->readBufferSize()];
        qDebug()<<socket->readBufferSize();
    }
}
...