简体   繁体   中英

Why does writing to this socket discard the read buffer (and is that really what's happening)?

Consider the following snippet:

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();

The goal of this snippet is to create two connected sockets by creating a QTcpServer that listens for incoming connections and connecting to it with another QTcpSocket . Once the connection is established, data is written to one of the sockets and it is closed.

QAbstractSocket::close() invokes disconnectFromHost() The documentation for QAbstractSocket::disconnectFromHost() clearly states that:

If there is pending data waiting to be written, QAbstractSocket will enter ClosingState and wait until all data has been written.

The next snippet enters the event loop briefly to process pending events and then attempts to read the string from the other socket:

QCoreApplication::processEvents();
qDebug() << clientSocket.readAll();

This prints "test" and all is well. Or perhaps not. If I modify the previous snippet by prepending a call to write() , the data can no longer be read from the socket:

clientSocket.write("test");
QCoreApplication::processEvents();
qDebug() << clientSocket.readAll();

This prints an empty string ( "" ) instead of the expected value from the previous run. Why can't the socket read the value this time?

Note: this only manifests itself on the Windows platform. Neither Linux nor Mac OS X builds of Qt exhibit this behavior, instead printing the expected value in both cases.

Second note: if you want to play with the code, there's a working Gist here: https://gist.github.com/nathan-osman/ee6116d120903db84384

Third note: here's a screenshot of a Wireshark capture of the TCP exchange:

在此处输入图片说明

Im not very familiar with Qt, but on Windows, there is no Fork. You are trying to fit to parallel tasks on the same thread, but you should have the client running on a different thread than the server.

You're writing asynchronous code in synchronous style in a way that doesn't ensure that you wait long enough for things to happen. Calling processEvents simply means "do any work that is currently available to do" not "do work and/or wait for work until no more work can possibly arrive". You treat it like the latter, but it means the former.

The simplest fix is not to do that.

Connect slots or functors to relevant socket signals, and return control to the event loop. Never use waitForXxx functions, they simply aren't specified sufficiently to allow use in all cases. Never mind the horrible reentrancy issues you'll face when reentering the event loop.

If there's no event loop in the thread where your code runs, spin up your own:

QEventLoop loop;

...
connect(serverSocket, &QAbstractSocket::disconnected,
        &loop, &QEventLoop::quit);
loop.exec(); // this will keep executing until the socked is disconnected

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM