Details
-
Bug
-
Resolution: Done
-
P2: Important
-
4.7.3
-
None
-
4920090da0fc937d171065694d5274221d2747c9.
Description
Use the unmodified TCP server example: http://qt-project.org/doc/qt-4.8/qt4-network.html#tcp-server
Use "ulimit -n 10" to make it easy to cause accept(2) to return EMFILE (Too many open files).
Run the TCP server. From another window, connect to it 10 times: for i in seq 10; do nc 127.0.0.1 1234 & done
The TCP server will go into an infinite loop, taking 100% CPU. strace shows:
accept(7, 0, NULL) = -1 EMFILE (Too many open files)
poll([
accept(7, 0, NULL) = -1 EMFILE (Too many open files)
poll([{fd=3, events=POLLIN}
, <snip>])
...
This means that a QTcpServer-based server can be permanently disabled, even if it only temporarily runs out of file descriptors.
The fact that accept(2) is failing is correct. The fact that no more connections can be accepted is correct, temporarily. But the correct behavior in this case is that once some client connections are closed, the server should gracefully recover and start accepting connections again.
The problem is that QTcpServerPrivate::readNotification, returns when it gets an error from socketEngine->accept(). It returns without addressing the fact that the listen socket is readable. As a result, it is called again immediately from the event loop. A better solution would be to provide a signal called "acceptError" that the caller can hook up to a slot. This slot needs to call QTcpServer::close() in order to avoid the loop, and then try some strategy to start listening again (perhaps use a timer to try QTcpServer::listen() again later, or perhaps use some other state in the application to know when to try listening again).
It appears that when a client connection disconnects, its socket becomes readable and, depending on how the event loop schedules the work, it might unblock the accept/poll loop. But until this happens, the server is wasting cycles doing the loop.
(Thanks to my colleague Marko Peltonen for researching this and proposing this solution.)
Attachments
Issue Links
- relates to
-
QTBUG-24247 QAbstractSocket::waitForReadyRead() crashes if the server has opened many files
- Open