QTcpSocket 读取错误

Posted

技术标签:

【中文标题】QTcpSocket 读取错误【英文标题】:QTcpSocket Read Error 【发布时间】:2014-08-13 16:34:54 【问题描述】:

我有一个基于 Qt 的 TCP 客户端和服务器,使用 QTcpServer 和 QTcpSocket 类进行通信。服务器使用 Qt 5.3.1 编译,客户端使用 Qt 4.8.1 编译。这样做是因为客户端是使用在 Ubuntu 12.04 上运行的 Qt 4.8.1 的框架的一部分。

由于我使用的类在两个 Qt 版本中都可用,我认为这不会造成问题。

但是我的客户端有一些奇怪的问题,它没有从服务器接收数据!我检查了服务器端,数据是从服务器发送的,我还可以使用wireshark查看线路上的数据包。但是在我的客户端代码上,数据没有到达!

我对此进行了一些调查,它使我得出一个奇怪的结论,即只有当我使用 QTcpSocket 的 read 方法时才会发生这种情况!如果我使用本机 POSIX 读取系统调用,我能够正确读取数据!请参阅下面的代码:

qDebug() << "QTcpSocket::bytesAvailable() gives" << m_pSocket->bytesAvailable();

char nData;

qint32 szReceived;

if(sizeof(char) != (szReceived = m_pSocket->read((char*)&nData,sizeof(char))))

    qDebug() << "Error reading data from QTcpSocket::read()" << m_pSocket->errorString();

else

    qDebug() << "QTcpSocket::read() returned" << szReceived;


int nDesc = m_pSocket->socketDescriptor();

if(sizeof(char) != (szReceived = read(nDesc, &nData,sizeof(char))))

    perror("Error reading data from POSIX read()");

else

    qDebug() << "POSIX read() returned" << szReceived;

这会产生以下输出:

QTcpSocket::bytesAvailable() gives 0 
Error reading data from QTcpSocket::read() "Network operation timed out" 
POSIX read() returned 1

POSIX系统调用如何按预期读取缓冲数据而Qt类无法读取?另外我没有设置任何socket选项,所以不知道为什么会报网络操作超时的错误!

【问题讨论】:

检查Qt示例:qt-project.org/doc/qt-5/qtnetwork-fortuneclient-example.html 【参考方案1】:

"read" 是 POSIX 中的阻塞调用,它一直等到数据到达。而 QTcpSocket 是非阻塞操作,它会立即返回缓冲的数据。在读取之前调用 waitForReadyRead

 socket->waitForReadyRead();
 if(sizeof(char) != (szReceived = m_pSocket->read((char*)&nData,sizeof(char))))

【讨论】:

【参考方案2】:

我认为这是对 QTcpSocket 概念的滥用。 QTcpSocket 实现异步架构,而 POSIX 读/写调用被阻塞,直到套接字上的 I/O 成功或错误。为readyRead信号处理槽中的读取要好得多。考虑一下:

class MyClient

  Q_OBJECT

...

private slots:

  readFromSocket();

;

在你的初始化中:

QObject::connect(
        m_pSocket, SIGNAL(readyRead()),
        this, SLOT(readFromSocket()));

真正的工作在这里完成:

void
MyClient::readFromSocket()

  QByteArray buffer = m_pSocket->readAll();
  // All your data in buffer. 

【讨论】:

【参考方案3】:

我知道 QTcpSocket 的非阻塞性质和 POSIX 读取调用的阻塞性质。不幸的是,我不能使用信号 readFromSocket,因为我的通信架构希望在每次通信(TCP 方式)之前发送一个标头,以查看为该特定消息流式传输的有效负载。因此,我必须等到至少收到标题。

我确实相信这与模式(阻塞或非阻塞)有关。我又做了一些测试,但没有一个是结论性的。在我的一项测试中,我尝试调用 waitForReadyRead 超时时间为 1ms、2ms、3ms。这仍然不足以让读取成功!我怀疑读取是否需要这样的时间才能从内核缓冲区读取到用户空间,因为我可以从 wireshark 清楚地看到消息是在 400 毫秒内收到的。

当我给-1作为waitForReadyRead的超时值时,读取成功!换句话说,只有当套接字像 POSIX 读取调用一样无限期等待时,读取才会成功。

我观察到的另一件奇怪的事情是,这个问题最初是在我运行使用 Qt 5.3.1 编译的服务器和使用 Qt 4.8.1 编译的客户端时观察到的。当我编译我的客户端以使用 Qt 5.3.1 时,我没有看到这个问题!!!我什至尝试使用 Qt 4.7.1 进行编译,它没有任何问题!!!

Qt 4.8.1 的套接字实现是否存在任何已知问题?很遗憾,我找不到太多关于此的信息。

【讨论】:

以上是关于QTcpSocket 读取错误的主要内容,如果未能解决你的问题,请参考以下文章

QTcpSocket,无法读取传入数据

如何使用 QTcpSocket 读取超过 8192 字节?

读取 QTcpSocket

无法写入 QRunnable 内的 QTcpSocket

QTcpSocket 仅每 ~0.5 秒读取一次数据,即使数据包非常小,有啥方法可以加快速度吗?

QTcpSocket 从服务器接收数据