QTcpSocket数据迟到了

时间:2017-12-10 16:31:56

标签: qt qtcpsocket qtcpserver

我正在使用QTCPSockets与我在Qt for 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);
    }
}

1 个答案:

答案 0 :(得分:2)

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

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