On 23/10/2018 20.43, Israel Brewster wrote:
I am using QSslSockets with a QTcpServer to create a simple
client/server program (is there a higher level API I could use
instead?). I have subclassed QTcpServer to create my server side sockets
as QSslSockets and call startServerEncryption(), but otherwise it is
just a standard QTcpServer.
When a socket first connects to the server, I make the following connection:
connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));
where clientConnection is the QSslSocket created by the QTcpServer.
Later, when using the socket (again on the server), I have the following
function to wait for data from the client:
////////////////////////////////////////////////////////////
/// \brief EZPCore::waitForResponseReady
/// \param socket
/// \param msec
/// \return true=data available, false=timeout/error
///
/// Documentation for QAbstractSocket "waitForReadyRead" says
/// "This function may fail randomly on Windows. Consider using the event loop
and the readyRead()
/// signal if your software will run on Windows."
/// so that's what this function does.
bool EZPCore::waitForResponseReady(QSslSocket *socket,int msec){
if(!socket || !socket->isValid() || !socket->isEncrypted() || socket->state()!=QAbstractSocket::ConnectedState)
return false; //there is something wrong with the socket, no point in waiting.
if(socket->bytesAvailable()>0)
return true;//success! Bytes are available!
QEventLoop wait; //don't block other operations while waiting
QTimer waitTimeout; //only wait a set length of time.
waitTimeout.setSingleShot(true);
connect(&waitTimeout,&QTimer::timeout,[&wait]{wait.exit(-1);});
connect(socket,&QAbstractSocket::disconnected,[&wait]{wait.exit(-2);}); //catch if the socket closes while waiting.
connect(socket,&QAbstractSocket::readyRead,[&wait]{wait.exit();}); //zero exit
waitTimeout.start(msec);
int result=wait.exec();
waitTimeout.stop(); //stop the timer if it is still running (probably unneeded?)
if(result<0)
return false; //not connected or timeout
//should only get here if result is 0, indicating readyRead signal
received.
//if we have bytes available, then return success (0), even if
//we had a timeout
if(socket->bytesAvailable()>0) //<--------We frequently crash here,
UNLESS I don't call "deleteLater()" on disconnect???
return true;
return false; //no bytes available
}
many times this works flawlessly. However, I am frequently getting a
crash when I call bytesAvailable() on the socket at the end of above
function - a crash that is resolved if I don't make the connection to
"deleteLater" when the socket is established. This tells me that the
socket is getting deleted during this event loop. What I don't
understand is why?
- When I come into this function, I check for
QAbstractSocket::ConnectedState on the socket, and return immediately if
not connected, which should mean that the socket is still connected when
this function starts.
- I connect the "disconnected" signal of this function up to exit the
event loop with a non-zero status should the socket disconnect during
the event loop (entirely possible, of course)
- The function returns immediately if the event loop exits with a
non-zero status, and the only way for the event loop to exit with a zero
status is for readyRead to be emitted.
As such, the only way for the crashing line of code to be executed
should be for a) the socket to be in a connected state (otherwise the
function wouldn't run), b) disconnected signal to NOT to be emitted
during the event loop (so still connected), and c) the readyRead signal
to be emitted. However, the crashing would indicate that the socket *is*
being deleted during the event loop, which indicates that the socket is
disconnecting. And yet I still get a readyRead signal?
Incidentally, If I connect the destroyed signal to the event loop exit,
I *do* catch that. So I can see the socket being destroyed, but not
being disconnected. So obviously I have an architecture issue here: the
socket is closing and being destroyed while I am still trying to read
from it. How can I fix this?
Hi, it could be that a new connection arrives not inside Qt's normal
event loop but in your wait.exec() call, i.e. some kind of recursion
could occur, I mean EZPCore::waitForResponseReady() calls wait.exec()
which calls another EZPCore::waitForResponseReady()...
The above is just a guess, but why not let Qt run its vanilla event loop
and refactor your code into 2 separate functions, one that takes care of
the disconnected signal and one that handles the readyRead signal.
Neither of them should require an eventloop inside them.
If you need to keep track of timeouts, you could use the QTimer but
connected to a separate function. Or just let the TCP protocol run its
course and disconnect automatically for you...
Rgrds Henry
_______________________________________________
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest