【问题标题】:QTcpSocket data arrives lateQTcpSocket 数据迟到
【发布时间】:2018-05-24 06:25:15
【问题描述】:

我正在使用 QTCPSockets 与我用 Qt 为 Raspberry Pi 编写的程序通信。相同的软件在我的 Mac(或 Windows,等等)上运行。 Pi 正在运行 QTCPServer。

我向它发送 JSON 数据,大多数情况下都可以。

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

感觉和这个错误报告有点联系:https://bugreports.qt.io/browse/QTBUG-58262 但我不确定是不是一样。

我尝试过waitForBytesWrittenflush,一开始似乎可以正常工作,但后来我又看到了这个问题。

我预计树莓派上的 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);
    }
}

【问题讨论】:

  • 您如何实现 JSON 消息之间的边界?能贴出收发消息的代码吗?
  • @bnaecker 谢谢,做到了。同时我重新启动了系统(Pi),直到现在我没有看到问题。但我需要一个可靠的系统,所以我想解决这些问题或解决它们。我不知道您对消息之间的“边界”是什么意思。我只是发送它们,当它们到达时,我将数据解析为对象
  • @Boy:如果我的回答 here 对您有所帮助,我会很高兴。 :)
  • @AntonioDias 是的,您的回答引导我走向正确的方向(与接受的答案相同,请参阅我的评论),谢谢!您的帖子中唯一缺少的是连接到dataReceived() 的插槽。我在那里投票赞成你的回答。

标签: qt qtcpsocket qtcpserver


【解决方案1】:

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

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

【讨论】:

  • 顺便说一句,我怎么知道我什么时候收到了整个消息? in.commitTransaction() 有时似乎是错误的,然后我返回。可能是这样,但至少我有一个完整的交易。
  • 谢谢!我花了一段时间才完全明白我做错了什么!我在客户端的ReadyRead 中添加了while(bytesAvailable()),但我没有在QTCPServer 中这样做!所以我错过了服务器实际上是不向其客户端广播数据的服务器。非常感谢您让我朝着正确的方向前进!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-10
  • 2013-09-09
相关资源
最近更新 更多