4

我正在为基于套接字接口的 Raspberry PI 开发应用程序。主要思想是 Raspberry 将连接到传感器,收集数据并通过 WiFi 将其发送到 Android 设备。在 Android 上,我可以与发送一些命令的传感器进行通信。我是这种开发的初学者,遵循一些关于 QTcpSocket 的教程,我创建了一个简单的客户端-服务器应用程序,但它只是一个方向。服务器监听客户端发送的内容。你能帮我把它改进成双向通信吗?我读过 QTcpSocket 不需要线程来解决这类问题,但我没有找到任何解决方案。

我将不胜感激任何帮助!

服务器.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();
}

客户端.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

2 回答 2

6

从架构的角度来看,您应该首先在服务器和客户端之间定义一些通信规则(消息流)。

然后根据定义的流程从(到)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 或其他标准化协议),您可以在消息的开头添加消息长度。

于 2013-06-17T15:01:10.230 回答
1

您需要做的就是从客户端或服务器的套接字写入/读取。TCP 连接已经是双向连接。

您的forever循环可能有一些问题ClientreadyRead您应该以与服务器相同的方式真正使用套接字上的信号并丢弃该forever循环。

以非阻塞方式处理键盘输入,而不是使用gets(). gets()将阻塞主线程并阻止它运行事件循环。这不是处理您的情况的最佳方式,因为您希望能够同时处理来自服务器和来自用户的数据。

也许看看这个关于控制台应用程序的键盘处理:

using-qtextstream-to-read-stdin-in-a-non-blocking-fashion

或者将其设为 GUI 应用程序并使用QPlainTextEdit.

于 2013-06-17T12:55:25.217 回答