QTcpSocket 数据迟到

QTcpSocket data arrives late

我正在使用 QTCPSockets 与我用 Qt 为 Raspberry Pi 编写的程序对话。同样的软件在我的 Mac(或 Windows,随便什么)上运行。 Pi 是 运行 一个 QTCPServer。

我向它发送 JSON 数据,大多数时候一切正常。

但有时,Pi 没有响应,数据似乎没有到达。但是,当我发送更多数据时,该数据没有被处理,但是之前的 Json 消息被处理了!就这样保持下去。所有消息现在都关闭1。发送新消息,触发上一条消息。

感觉与此错误报告有点关联:https://bugreports.qt.io/browse/QTBUG-58262 但是不知道是不是一样

我已经尝试了 waitForBytesWrittenflush 并且一开始似乎有效,但后来我又看到了这个问题。

我希望 Pi 上的 TCP 缓冲区不会被刷新,但我现在知道如何确保立即处理所有数据。

根据要求,这里是一些源代码: 这是客户端软件:

Client::Client() : tcpSocket(new QTcpSocket(this)), in(tcpSocket)
{
    connect(tcpSocket, &QIODevice::readyRead, this, &Client::readData);
    connect(tcpSocket, &QTcpSocket::connected, this, &Client::connected);
    connect(tcpSocket, &QTcpSocket::stateChanged, this, &Client::onConnectionStateChanged);
    void (QAbstractSocket:: *sig)(QAbstractSocket::SocketError) = &QAbstractSocket::error;
    connect(tcpSocket, sig, this, &Client::error);
}

void Client::connectTo(QString ip, int port) {
    this->ip = ip;
    this->port = port;
    tcpSocket->connectToHost(ip, port);
}

void Client::reconnect() {
    connectTo(ip, port);
}

void Client::disconnect()
{
    tcpSocket->disconnectFromHost();
}

void Client::connected()
{
    qDebug() << TAG << "connected!";
}

void Client::error(QAbstractSocket::SocketError error)
{
    qDebug() << TAG << error;
}

void Client::sendData(const QString& data)
{
    bool connected = (tcpSocket->state() == QTcpSocket::ConnectedState);
    if (!connected) {
        qDebug() << TAG << "NOT CONNECTED!";
        return;
    }

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_7);

    out << data;
    tcpSocket->write(block);
    tcpSocket->flush();
}

void Client::sendData(const QByteArray& data) {
    bool connected = (tcpSocket->state() == QTcpSocket::ConnectedState);
    if (!connected) {
        qDebug() << TAG << " is NOT connected!";
        return;
    }
    tcpSocket->write(data);
    tcpSocket->flush();
}

void Client::readData()
{
    in.startTransaction();

    QString data;
    in >> data;

    if (!in.commitTransaction())
    {
        return;
    }

    emit dataReceived(data);
}

void Client::onConnectionStateChanged(QAbstractSocket::SocketState state)
{
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        connectionState = "Not connected";
        break;
    case QAbstractSocket::ConnectingState:
        connectionState = "connecting";
        break;
    case QAbstractSocket::ConnectedState:
        connectionState = "connected";
        break;
    default:
        connectionState = QString::number(state);
    }

    qDebug() << TAG << " connecting state: " << state;

    emit connectionStateChanged(connectionState);

    if (state == QAbstractSocket::UnconnectedState) {
        QTimer::singleShot(1000, this, &Client::reconnect);
    }
}

这里是服务器部分:

Server::Server()
{
    tcpServer = new QTcpServer(this);

    connect(tcpServer, &QTcpServer::newConnection, this, &Server::handleConnection);

    tcpServer->listen(QHostAddress::Any, 59723);

    QString ipAddress;
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    // use the first non-localhost IPv4 address
    for (int i = 0; i < ipAddressesList.size(); ++i) {
        if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
            ipAddressesList.at(i).toIPv4Address()) {
            ipAddress = ipAddressesList.at(i).toString();
            break;
        }
    }

    // if we did not find one, use IPv4 localhost
    if (ipAddress.isEmpty())
        ipAddress = QHostAddress(QHostAddress::LocalHost).toString();

    qDebug() << TAG <<  "ip " << ipAddress << " serverport: " << tcpServer->serverPort();
}

void Server::clientDisconnected()
{
    QTcpSocket *client = qobject_cast<QTcpSocket *>(QObject::sender());

    int idx = clients.indexOf(client);
    if (idx != -1) {
        clients.removeAt(idx);
    }

    qDebug() << TAG << "client disconnected: " << client;

    client->deleteLater();
}

void Server::handleConnection()
{
    qDebug() << TAG << "incoming!";

    QTcpSocket* clientConnection = tcpServer->nextPendingConnection();
    connect(clientConnection, &QAbstractSocket::disconnected, this, &Server::clientDisconnected);
    connect(clientConnection, &QIODevice::readyRead, this, &Server::readData);
    clients.append(clientConnection);
    broadcastUpdate(Assets().toJson());
}

void Server::readData()
{
    QTcpSocket *client = qobject_cast<QTcpSocket *>(QObject::sender());

    QDataStream in(client);
    in.startTransaction();

    QString data;
    in >> data;

    if (!in.commitTransaction())
    {
        return;
    }

...
    // here I do something with the data. I removed that code as it is
    // not necessary for this issue
...

    broadcastUpdate(data);
}

void Server::broadcastUpdate(const QString& data)
{
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_7);

    out << data;

    foreach(QTcpSocket* client, clients) {
        bool connected = (client->state() == QTcpSocket::ConnectedState);
        if (!connected) {
            qDebug() << TAG << client << " is NOT connected!";
            continue;
        }
        client->write(block);
    }
}

我认为问题出在你的 void Client::readData() 上:你必须以这样的方式编写它,以便从其中的套接字读取所有可用数据(通常它是用 while (socket->bytesAvailable() > 0) { ... } 循环编写的) .

这是因为 readyRead() 信号发出的方式:远程对等方可能会向您发送任何非零数量的数据包,并且您的套接字将发出任何非零数量的 readyRead() 信号。在您的情况下,服务器似乎发送了两条消息,但它们只会导致客户端发出一个 readyRead() 信号。