为什么我的代码不能读取QTcpSocket上可用的字节数?想法?

时间:2013-05-20 15:40:26

标签: c++ qt sockets qtcpsocket

我在循环体中有以下代码片段,负责从QTcpSocket读取数据(nntp是指向QTcpSocket的指针)。

std::vector<char> buffer;
int bytesAvailable = nntp->bytesAvailable();
qDebug() << "bytesAvailable: "<<bytesAvailable;
if(bytesAvailable <= 0) break;
buffer.resize(bytesAvailable);
bytesRead = nntp->read(&buffer[0], bytesAvailable);
qDebug() << (nntp->state() == QAbstractSocket::ConnectedState);
qDebug() << "bytesRead: "<<bytesRead;

间歇性地,这会输出类似于以下内容的内容:

bytesAvailable:  24 
true 
bytesRead:  0 

我的代码错误表现了。这对我来说似乎很奇怪,并暗示我完全误解了QTcpSockets的工作原理。当然,如果bytesAvailable&gt; 0然后后续读取将意味着bytesAvailable字节可以读入缓冲区,在这种情况下bytesRead应该== bytesAvailable。或者我错过了什么?我目前的怀疑是它可能是某种记忆腐败......

编辑:抛出一些nntp.errorString()消息报告在此失败期间,“网络操作超时”。我需要调查这意味着什么......(想法?)

编辑2:似乎“网络操作超时”只是意味着读取超时。当代码按预期工作时(即间歇性地),我仍然会得到这个'错误'。

编辑3:可以找到上述代码片段的完整算法上下文at this pastebin link

编辑4:编辑3中的功能稍有不同但仍然存在同样的问题this newer pastebin link

3 个答案:

答案 0 :(得分:3)

我发现了这个问题:我试图读取的QTcpSocket属于另一个线程。即使字节根据QIODevice的缓冲区可用,也因此无法读取。

因此:

*始终确保您要读取的套接字属于您要阅读的主题*

为了解决这个问题,正如泰勒上面提到的那样,人们可以利用QTcpSocket的信号和插槽基础设施(首选)。这有适当的线程基础设施,理论上应该使事情变得更简单。

OR

要格外小心,

(a)利用自己的QThread,将包含QTcpSocket的对象移动到此QThread

然后,

(b)在另一个线程的阻塞读取循环中使用QTcpSocket的waitForReadyRead。

后一种方法比较困难,因为如果想要在将来的读写中保留QTcpSocket用于其他线程,那么在将其移动到另一个线程并由该另一个线程处理之后,必须将其移回主线程之前它可以被移动另一个线程。 - 让我头疼只是想说出来!当然,有人可能选择保留相同的QTcpSocket工作线程,以便只需要移动一次,或者每次需要QTcpSocket时简单创建一个新的QTcpSocket,将其移动到自己的QThread,然后在完成后立即删除它用。

基本上,如果可以,请选择第一个信号和插槽方法。

答案 1 :(得分:2)

我还没有遇到这个精确的问题(可能是因为我使用的是不同版本的Qt),但我建议尝试的是从循环切换到事件驱动的方法。如果您的循环在主线程中运行,那么对象无法传递排队信号(因为QTcpSocket类可能在内部执行),这可能就是您查看&#34;网络操作超时& #34;

所以连接一些基本的QTcpSocket信号:

connect(nntp, SIGNAL(disconnected()),
        this, SLOT(onDisconnected()));
connect(nntp, SIGNAL(readyRead()),
        this, SLOT(onReadyRead()));
connect(nntp, SIGNAL(error(QAbstractSocket::SocketError)),
        this, SLOT(onSocketError(QAbstractSocket::SocketError)));

然后把你现有的&#34;阅读&#34; onReadyRead中的代码。

也许你的问题无关紧要,但我最近在同事写的代码中看到了类似的问题,这就是我修复它的方法。

答案 2 :(得分:2)

如果bytesAvailable()报告QIODevice内部缓冲区中等待的数据大小加上操作系统报告的大小(例如,在ioctl(fd,FIONREAD,&bytesCount)获取的Linux中),可能会发生什么? )。

这本身就有意义,但是为了能够在没有事件循环的情况下从QTcpSocket读取这些字节,必须在自己的循环中调用waitForReadyRead()。否则,来自内核缓冲区的数据不会进入QIODevice的缓冲区。

如果您的代码在套接字上没有任何内容可读时不允许阻止,并且您不想将其重新整形为事件驱动结构,请使用较小的值来waitForReadyRead超时在实践中,它会表现得好像没有阻挡。

如果您还在没有事件循环的情况下写入套接字,也不要忘记调用waitForBytesWritten()