【发布时间】:2015-07-07 20:19:36
【问题描述】:
考虑以下 sn-p:
QTcpServer server;
server.listen(QHostAddress::LocalHost);
QTcpSocket clientSocket;
clientSocket.connectToHost(server.serverAddress(), server.serverPort());
// ...wait for connection to succeed...
QTcpSocket *serverSocket = server.nextPendingConnection();
serverSocket->write("test");
serverSocket->close();
这个 sn-p 的目标是通过创建一个 QTcpServer 来创建两个连接的套接字,该 QTcpServer 侦听传入连接并与另一个 QTcpSocket 连接到它。建立连接后,数据将写入其中一个套接字并关闭。
QAbstractSocket::close() invokes disconnectFromHost() documentation for QAbstractSocket::disconnectFromHost() 明确指出:
如果有等待写入的未决数据,QAbstractSocket 将进入 ClosingState 并等待直到所有数据都已写入。
下一个 sn-p 短暂进入事件循环处理挂起的事件,然后尝试从另一个套接字读取字符串:
QCoreApplication::processEvents();
qDebug() << clientSocket.readAll();
这会打印出"test",一切都很好。或者也许不是。如果我通过预先调用write() 来修改之前的sn-p,则无法再从套接字读取数据:
clientSocket.write("test");
QCoreApplication::processEvents();
qDebug() << clientSocket.readAll();
这将打印一个空字符串 (""),而不是上一次运行的预期值。为什么socket这次不能读取值了?
注意:此仅在 Windows 平台上体现。 Qt 的 Linux 和 Mac OS X 版本都没有表现出这种行为,而是在两种情况下都打印预期值。
第二点:如果你想玩代码,这里有一个工作要点:https://gist.github.com/nathan-osman/ee6116d120903db84384
第三点:这是 Wireshark 捕获 TCP 交换的屏幕截图:
【问题讨论】:
-
我的猜测:由于套接字的另一端已关闭,我希望尝试写入它会使套接字处于错误状态,并可能导致它自动关闭。之后是否仍然可以从套接字读取数据可能取决于实现。
-
@HarryJohnston 第一次写入和关闭操作直到
QCoreApplication::processEvents();行才发生(我用调试器验证了这一点)。不过,它们可能仍然是乱序处理的。 -
如果不能保证排序,它可能仅在 UNIX 上工作,因为 Qt 恰好选择在处理 serverSocket.close() 之前处理 clientSocket.write()。但这也可能是由于底层套接字实现的差异。
-
@HarryJohnston 我添加了 TCP 交换的屏幕截图,以防有助于阐明事件的顺序。第一个
write()立即得到确认,然后在客户端套接字写入任何内容之前发送并确认FIN数据包。 -
这与 Linux / MacOSX 上的事件序列相比如何?