2013-05-20 11 views
2

我在负责从QTcpSocket读取数据的循环体中有以下代码片段(nntp是指向QTcpSocket的指针)。为什么我的代码不能读取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> 0,那么随后的读取将意味着bytesAvailable字节可以读入缓冲区,在这种情况下bytesRead应该== bytesAvailable。或者我错过了什么?我目前的怀疑是,它可能是某种形式的内存损坏..

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

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

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

编辑4:编辑3,但仍与仍然同样的问题略有不同版本的功能是在this newer pastebin link

+0

我真的不喜欢这种结构:'&buffer [0]'。相反,请尝试'buffer = nntp-> readAll();'。 – Amartel

+0

感谢您的建议Amartel,但切换到QByteArray,然后做一个readAll,然后使用QByteArray的大小来确定读取的字节数仍然会导致相同的问题 –

回答

3

我发现了这个问题:我一直试图读取的QTcpSocket属于不同的线程。即使字节根据QIODevice的缓冲区可用,但由于这一点,它们不能被读取。

因此:

*务必确保您想从中读取数据的插座属于您要做好阅读*

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

OR

是超级谨慎和

(一)利用者自己的QThread,移动包含与QTcpSocket这个QThread的

那么对象,

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

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

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

2

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

所以连一些基本的信号与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))); 

然后把你现有的“阅读”代码onReadyRead。

也许你的问题是不相关的,但我最近看到一个同事编写的代码中存在类似的问题,这就是我如何解决它的问题。

+0

谢谢泰勒 - 我更喜欢信号和插槽的方式做事情,我可能会在未来改变这种做法。我之所以选择一个循环是因为我需要能够读取一定数量的格式化数据,这些格式化数据根据多个转义序列进行标记。在循环内,根据这些令牌解析数据相对容易,而且在我知道它应该可用的确切时刻。话虽如此,我的方法显然是越野车,所以我可能最终需要切换到信号和SLOTs像你推荐.. –

2

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

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

如果你的代码是不允许块时没有什么插座上阅读,而你不想把它重塑成一个事件驱动的结构,使用一个小的值waitForReadyRead的超时时间,这样在实践中它会表现得好像没有阻塞。

也不要忘记打电话给waitForBytesWritten()以及如果你也写入没有事件循环的套接字。

+0

谢谢丹尼尔,这是有道理的。我确实在完整循环的上下文中使用了waitForReadyRead。请参阅原始帖子中的编辑3获取链接。 –

+0

我将它从外循环移动到只是在阅读'bytesAvailable()'之前,看看这是否有所作为,尤其是因为外循环是do..while而不是一段时间.. do –

+0

谢谢Daniel,我试过你的建议(见编辑4的链接代码),但我仍然有同样的问题 –

相关问题