Qt-server发送包,但并非所有包都被收到

时间:2015-06-30 16:21:49

标签: c++ qt

我在Qt中创建了一个服务器 - 客户端通信,主服务器功能如下所示:

void Server::sendData(QPair<QString, QPair<QString, QVariant> > data)
{
//! [5]
    //QString data = "";
    qDebug() << "Transmitted data in send-data-function is: " + data.first + " " + data.second.first + " " + QString::number(data.second.second.toDouble());
    QPair<QString, QPair<QString, QVariant> > send_data = data;
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_0);
    out << (quint16)0;
    out << send_data;
    out.device()->seek(0);
    out << (quint16)(block.size() - sizeof(quint16));
    if(Server::clientConnection != NULL)
    {
        //qDebug() << "New Connection: " << Server::clientConnection->peerAddress().toString() << " on Port: " << Server::clientConnection->peerPort();
        QVariant ipAddr_QVar(Server::clientConnection->peerAddress().toString());
        //qDebug() << "New qvariant: " << ipAddr_QVar;

        clientConnection->write(block);
    }
    else
        qDebug() << "No connection!";
}

主要客户端功能如下:

Client::Client(QString purpose) : networkSession(0)
{
    Client::purpose = purpose;
    tcpSocket = new QTcpSocket;
    Client::blockSize = 0;
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readData()));
    connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(displayError(QAbstractSocket::SocketError)));

    QNetworkConfigurationManager manager;
    if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
    {
        // Get saved network configuration
        QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
        settings.beginGroup(QLatin1String("QtNetwork"));
        const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
        settings.endGroup();

        // If the saved network configuration is not currently discovered use the system default
        QNetworkConfiguration config = manager.configurationFromIdentifier(id);
        if ((config.state() & QNetworkConfiguration::Discovered) !=
            QNetworkConfiguration::Discovered) {
            config = manager.defaultConfiguration();
        }

        networkSession = new QNetworkSession(config, this);
        connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened()));
    }
}

void Client::readData()
{
    QDataStream in(tcpSocket);
    in.setVersion(QDataStream::Qt_5_0);
    if (blockSize == 0) {
        if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
            return;

        in >> blockSize;
    }
    if (tcpSocket->bytesAvailable() < blockSize)
    {
        qDebug() << tcpSocket->bytesAvailable() << ' ' << blockSize;
        return;
    }
    in >> data;
    blockSize = 0;
    qDebug() << "Client got new data!";
    qDebug() << data.first << " " << " " << data.second.first << " " << data.second.second.toInt();
    emit Client::gotData(data);

}

两者均来自QT示例 我现在的问题是来自服务器的调试消息如下所示:

"Transmitted data in send-data-function is: STP S 0"
"Transmitted data in send-data-function is: STP S 1"
"Transmitted data in send-data-function is: STP S 2"
"Transmitted data in send-data-function is: STP S 3"
"Transmitted data in send-data-function is: STP S 4"
...
"Transmitted data in send-data-function is: STP S 96"
"Transmitted data in send-data-function is: STP S 97"
"Transmitted data in send-data-function is: STP S 98"
"Transmitted data in send-data-function is: STP S 99"

来自客户端函数的调试输出如下:

Client got new data!
"STP"     "S"   2
"Got the following new data: STP S 2"
Current Movement Status: 
Client got new data!
"STP"     "S"   3
Client got new data!
"STP"     "S"   4
"Got the following new data: STP S 3"
Current Movement Status: 
"Got the following new data: STP S 4"
Current Movement Status: 

这就是我直接在接收函数中得到的,所以我假设这些包永远不会到达客户端。因此,我想知道在创建最小工作示例之前是否有任何可以做的事情来缩小可能的错误(在Server之后 - 和Client - 类都有很多与外部的连接)。

1 个答案:

答案 0 :(得分:1)

第一步,与任何 IO相关问题一样,添加错误检查,例如:

...
in >> data;
qDebug() << "in status after data read:" << in.status();
Q_ASSERT(in.status() == QDataStream::Ok);
...

在读完之后也一样。

然后,in>>data之前的长度检查看起来很可疑,它可能会在有足够数据之前尝试阅读。但是,我建议不要在完全使用复杂数据的套接字上使用QDataStream,因为它不会从错误中恢复,包括数据太少。

相反,这样做:

  • 在发件人方面,使用QDataStream写入QByteArray,这样您就可以获得QDataStream格式的完整数据。然后直接在套接字上发送字节数组的长度和内容。
  • 在接收端,接收长度然后接收并放入许多字节的QByteArray。您现在应该具有与发送方相同的字节数组。然后只需在该字节数组上使用QDataStream,保证包含有效数据(当然,只要你在两边设置相同的QByteArray选项)。

您可以使用QDataStream发送和接收长度,因为它很短且已知长度,但更复杂和更长的数据最好直接写为原始字节。