Reconnecting using QAbstractSocket::connectToHost
-
I'm facing a problem while reconnecting to the server. I've defined a class by the name Persistance_Connect whose purpose is to keep the connection alive. The constructor of the class contains:
QObject::connect(&socket, &QAbstractSocket::disconnected, this, [](){qDebug() <<"Disconnected!";}); QObject::connect(&socket, &QAbstractSocket::errorOccurred, this, &Persistance_Connect::onErr);
After errorOccured, connectToHost() is called but the client doesn't reconnects to the server.
void Persistance_Connect::onErr(QAbstractSocket::SocketError error) { qDebug() << "onErr is called"; switch (error) { case QAbstractSocket::AddressInUseError: qDebug()<< "SOCKET ERROR: Address is already in use"; break; case QAbstractSocket::ConnectionRefusedError: qDebug()<< "SOCKET ERROR: Connection refused"; break; case QAbstractSocket::HostNotFoundError: qDebug()<< "SOCKET ERROR: Host not found"; break; case QAbstractSocket::RemoteHostClosedError: qDebug()<< "SOCKET ERROR: Remote host closed"; break; } socket.disconnectFromHost(); qDebug() << "Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); }
The output is as follows after the server closes the connection
Server_Addr: "192.168.253.102" onErr is called SOCKET ERROR: Remote host closed Disconnected! Trying to Reconnect to "192.168.253.102" : 7777
After the above output, Client doesn't try to reconnect to the server.
-
I'm facing a problem while reconnecting to the server. I've defined a class by the name Persistance_Connect whose purpose is to keep the connection alive. The constructor of the class contains:
QObject::connect(&socket, &QAbstractSocket::disconnected, this, [](){qDebug() <<"Disconnected!";}); QObject::connect(&socket, &QAbstractSocket::errorOccurred, this, &Persistance_Connect::onErr);
After errorOccured, connectToHost() is called but the client doesn't reconnects to the server.
void Persistance_Connect::onErr(QAbstractSocket::SocketError error) { qDebug() << "onErr is called"; switch (error) { case QAbstractSocket::AddressInUseError: qDebug()<< "SOCKET ERROR: Address is already in use"; break; case QAbstractSocket::ConnectionRefusedError: qDebug()<< "SOCKET ERROR: Connection refused"; break; case QAbstractSocket::HostNotFoundError: qDebug()<< "SOCKET ERROR: Host not found"; break; case QAbstractSocket::RemoteHostClosedError: qDebug()<< "SOCKET ERROR: Remote host closed"; break; } socket.disconnectFromHost(); qDebug() << "Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); }
The output is as follows after the server closes the connection
Server_Addr: "192.168.253.102" onErr is called SOCKET ERROR: Remote host closed Disconnected! Trying to Reconnect to "192.168.253.102" : 7777
After the above output, Client doesn't try to reconnect to the server.
@pingal said in Reconnecting using QAbstractSocket::connectToHost:
socket.disconnectFromHost(); qDebug() << "Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol);
I would guess you are trying to reconnect (a) from within existing connect
errorOccurred
, which just might be problematic and (b) much too early after disconnectFromHost():Attempts to close the socket. If there is pending data waiting to be written, QAbstractSocket will enter ClosingState and wait until all data has been written. Eventually, it will enter UnconnectedState and emit the disconnected() signal.
Try doing just the
socket.disconnectFromHost();
here (assuming that is safe insideerrorOccured
, else do it on a timer). Do the reconnect when you have received the appropriatedisconnected()
signal? -
Thanks for the reply,
So now my connections are as following:QObject::connect(&socket, &QAbstractSocket::disconnected, this, &Persistance_Connect::onDisconnected); QObject::connect(&socket, &QAbstractSocket::errorOccurred, this, &Persistance_Connect::onErr);
Here is the onErr:
void Persistance_Connect::onErr(QAbstractSocket::SocketError error) { qDebug() << "onErr is called"; switch (error) { case QAbstractSocket::AddressInUseError: qDebug()<< "SOCKET ERROR: Address is already in use"; break; case QAbstractSocket::ConnectionRefusedError: qDebug()<< "SOCKET ERROR: Connection refused"; break; case QAbstractSocket::HostNotFoundError: qDebug()<< "SOCKET ERROR: Host not found"; break; case QAbstractSocket::RemoteHostClosedError: qDebug()<< "SOCKET ERROR: Remote host closed"; break; } socket.disconnectFromHost(); }
And here is my disconnect handler
void Persistance_Connect::onDisconnected() { qDebug() << "Disconnected! Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); }
Still it doesn't reconnect. Here is the output when i tried to close connection from server after a succesfull connect
Connected! Server_Addr: "192.168.253.102" onErr is called SOCKET ERROR: Remote host closed Disconnected! Trying to Reconnect to "192.168.253.102" : 7777
-
Thanks for the reply,
So now my connections are as following:QObject::connect(&socket, &QAbstractSocket::disconnected, this, &Persistance_Connect::onDisconnected); QObject::connect(&socket, &QAbstractSocket::errorOccurred, this, &Persistance_Connect::onErr);
Here is the onErr:
void Persistance_Connect::onErr(QAbstractSocket::SocketError error) { qDebug() << "onErr is called"; switch (error) { case QAbstractSocket::AddressInUseError: qDebug()<< "SOCKET ERROR: Address is already in use"; break; case QAbstractSocket::ConnectionRefusedError: qDebug()<< "SOCKET ERROR: Connection refused"; break; case QAbstractSocket::HostNotFoundError: qDebug()<< "SOCKET ERROR: Host not found"; break; case QAbstractSocket::RemoteHostClosedError: qDebug()<< "SOCKET ERROR: Remote host closed"; break; } socket.disconnectFromHost(); }
And here is my disconnect handler
void Persistance_Connect::onDisconnected() { qDebug() << "Disconnected! Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); }
Still it doesn't reconnect. Here is the output when i tried to close connection from server after a succesfull connect
Connected! Server_Addr: "192.168.253.102" onErr is called SOCKET ERROR: Remote host closed Disconnected! Trying to Reconnect to "192.168.253.102" : 7777
-
How do we know for sure that whatever the server is it accepts reconnections? After the
disconnectFromHost()
in this application, try running e.g. a new instance of this application and verify that can connect first time? -
Put a slot on void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState) and monitor how the state is changing.
-
Not sure if it's relevant but try putting the
disconnectFromHost()
and/or theconnectToHost()
on aQTimer::singleShot()
so that they do not happen while still inside a slot on the old connection, in case that makes any difference? -
Temporarily try using a second, distinct
QAbstractSocket socket2
(persistent, same place as wherever your currentsocket
is declared) for the re-connect, just in case there is an issue on re-connecting the existing one?
-
-
-
How do we know for sure that whatever the server is it accepts reconnections? After the
disconnectFromHost()
in this application, try running e.g. a new instance of this application and verify that can connect first time? -
Put a slot on void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState) and monitor how the state is changing.
-
Not sure if it's relevant but try putting the
disconnectFromHost()
and/or theconnectToHost()
on aQTimer::singleShot()
so that they do not happen while still inside a slot on the old connection, in case that makes any difference? -
Temporarily try using a second, distinct
QAbstractSocket socket2
(persistent, same place as wherever your currentsocket
is declared) for the re-connect, just in case there is an issue on re-connecting the existing one?
- How do we know for sure that whatever the server is it accepts reconnections? After the
disconnectFromHost()
in this application, try running e.g. a new instance of this application and verify that can connect first time?
Yes, the server accepts reconnection and i've tried that using another instance.
- Put a slot on void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState) and monitor how the state is changing.
Here is the output when the client is connected to the server
QAbstractSocket::HostLookupState QAbstractSocket::ConnectingState QAbstractSocket::ConnectedState Connected! Server_Addr: "192.168.253.102"
And when the server closes the connection
onErr is called SOCKET ERROR: Remote host closed QAbstractSocket::ClosingState QAbstractSocket::UnconnectedState Disconnected! Trying to Reconnect to "192.168.253.102" : 7777 QAbstractSocket::HostLookupState QAbstractSocket::ConnectingState
- Not sure if it's relevant but try putting the
disconnectFromHost()
and/or theconnectToHost()
on aQTimer::singleShot()
so that they do not happen while still inside a slot on the old connection, in case that makes any difference?
Have not tried it yet
- Temporarily try using a second, distinct
QAbstractSocket socket2
(persistent, same place as wherever your currentsocket
is declared) for the re-connect, just in case there is an issue on re-connecting the existing one?
Have not tried it yet
-
-
- How do we know for sure that whatever the server is it accepts reconnections? After the
disconnectFromHost()
in this application, try running e.g. a new instance of this application and verify that can connect first time?
Yes, the server accepts reconnection and i've tried that using another instance.
- Put a slot on void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState) and monitor how the state is changing.
Here is the output when the client is connected to the server
QAbstractSocket::HostLookupState QAbstractSocket::ConnectingState QAbstractSocket::ConnectedState Connected! Server_Addr: "192.168.253.102"
And when the server closes the connection
onErr is called SOCKET ERROR: Remote host closed QAbstractSocket::ClosingState QAbstractSocket::UnconnectedState Disconnected! Trying to Reconnect to "192.168.253.102" : 7777 QAbstractSocket::HostLookupState QAbstractSocket::ConnectingState
- Not sure if it's relevant but try putting the
disconnectFromHost()
and/or theconnectToHost()
on aQTimer::singleShot()
so that they do not happen while still inside a slot on the old connection, in case that makes any difference?
Have not tried it yet
- Temporarily try using a second, distinct
QAbstractSocket socket2
(persistent, same place as wherever your currentsocket
is declared) for the re-connect, just in case there is an issue on re-connecting the existing one?
Have not tried it yet
@pingal said in Reconnecting using QAbstractSocket::connectToHost:
QAbstractSocket::ConnectingState
Looks to me like the client side is doing its bit but the server side is not accepting the reconnection, in a timely fashion. Do try those last 2 suggestions, especially the second one.
Are you in charge of (have the code to) the server side, or is that third-party?
- How do we know for sure that whatever the server is it accepts reconnections? After the
-
- How do we know for sure that whatever the server is it accepts reconnections? After the
disconnectFromHost()
in this application, try running e.g. a new instance of this application and verify that can connect first time?
Yes, the server accepts reconnection and i've tried that using another instance.
- Put a slot on void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState) and monitor how the state is changing.
Here is the output when the client is connected to the server
QAbstractSocket::HostLookupState QAbstractSocket::ConnectingState QAbstractSocket::ConnectedState Connected! Server_Addr: "192.168.253.102"
And when the server closes the connection
onErr is called SOCKET ERROR: Remote host closed QAbstractSocket::ClosingState QAbstractSocket::UnconnectedState Disconnected! Trying to Reconnect to "192.168.253.102" : 7777 QAbstractSocket::HostLookupState QAbstractSocket::ConnectingState
- Not sure if it's relevant but try putting the
disconnectFromHost()
and/or theconnectToHost()
on aQTimer::singleShot()
so that they do not happen while still inside a slot on the old connection, in case that makes any difference?
Have not tried it yet
- Temporarily try using a second, distinct
QAbstractSocket socket2
(persistent, same place as wherever your currentsocket
is declared) for the re-connect, just in case there is an issue on re-connecting the existing one?
Have not tried it yet
@pingal
UPDATE
Especially if you do find that a newsocket2
does work: on your existingsocket
try calling bool QIODevice::reset() after disconnect before reconnect.And/or, read https://bugreports.qt.io/browse/QTBUG-18082?focusedCommentId=170619&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-170619, which seems to me to be your issue, re: my suggestion that after error there might be a problem. That is claiming
The issue here is that connectToHost() is being called from within a slot connected to error() and that doesn't work, making ComEngine::connectToHost() into a slot and using QMetaObject::invokeMethod(this, "connectToHost", Qt::QueuedConnection); to have the reconnection attempt be made after works like a charm.
"Bug" is over 10 years ago, but that doesn't stop it possibly still be applicable in QT... :) Read through https://stackoverflow.com/questions/11600288/qtcpsocket-client-auto-reconnect too.
- How do we know for sure that whatever the server is it accepts reconnections? After the
-
@pingal said in Reconnecting using QAbstractSocket::connectToHost:
QAbstractSocket::ConnectingState
Looks to me like the client side is doing its bit but the server side is not accepting the reconnection, in a timely fashion. Do try those last 2 suggestions, especially the second one.
Are you in charge of (have the code to) the server side, or is that third-party?
Looks to me like the client side is doing its bit but the server side is not accepting the reconnection
I'm using a simple server i.e. netcat for debugging purposes and it works fine, I've even checked the signals from client to server in wireshark to verify that the client indeed is not requesting connection after disconnect, contrary to the QAbstractSocket::ConnectingState
-
Looks to me like the client side is doing its bit but the server side is not accepting the reconnection
I'm using a simple server i.e. netcat for debugging purposes and it works fine, I've even checked the signals from client to server in wireshark to verify that the client indeed is not requesting connection after disconnect, contrary to the QAbstractSocket::ConnectingState
@pingal
Point taken. Try the suggestions I have posted in previous 2 posts.Also i have just spotted what I thought in the docs for errorOccurred():
When this signal is emitted, the socket may not be ready for a reconnect attempt. In that case, attempts to reconnect should be done from the event loop. For example, use a QTimer::singleShot() with 0 as the timeout.
-
@pingal
Point taken. Try the suggestions I have posted in previous 2 posts.Also i have just spotted what I thought in the docs for errorOccurred():
When this signal is emitted, the socket may not be ready for a reconnect attempt. In that case, attempts to reconnect should be done from the event loop. For example, use a QTimer::singleShot() with 0 as the timeout.
@JonB said in Reconnecting using QAbstractSocket::connectToHost:
@pingal
Point taken. Try the suggestions I have posted in previous 2 posts.Also i have just spotted what I thought in the docs for errorOccurred():
When this signal is emitted, the socket may not be ready for a reconnect attempt. In that case, attempts to reconnect should be done from the event loop. For example, use a QTimer::singleShot() with 0 as the timeout.
using QTimer::singleShot like below:
void Persistance_Connect::onDisconnected() { qDebug() << "Disconnected! Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; QTimer::singleShot(0, this, SLOT(connect("192.168.253.102", 7777))); socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); }
output:
QMetaObject::invokeMethod: No such method Persistance_Connect::connect()
I think I'm doing it wrong, kindly ignore my ignorance.
I've created socket2 for reconnection phase, same results.
-
@JonB said in Reconnecting using QAbstractSocket::connectToHost:
@pingal
Point taken. Try the suggestions I have posted in previous 2 posts.Also i have just spotted what I thought in the docs for errorOccurred():
When this signal is emitted, the socket may not be ready for a reconnect attempt. In that case, attempts to reconnect should be done from the event loop. For example, use a QTimer::singleShot() with 0 as the timeout.
using QTimer::singleShot like below:
void Persistance_Connect::onDisconnected() { qDebug() << "Disconnected! Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; QTimer::singleShot(0, this, SLOT(connect("192.168.253.102", 7777))); socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); }
output:
QMetaObject::invokeMethod: No such method Persistance_Connect::connect()
I think I'm doing it wrong, kindly ignore my ignorance.
I've created socket2 for reconnection phase, same results.
@pingal said in Reconnecting using QAbstractSocket::connectToHost:
I've created socket2 for reconnection phase, same results.
That stumps me. If you can re-connect from a separate program but not from a brand new socket in the same program I don't know what to tell you. You can see from those links other people claimed to get it working.
The code you tried might better be, say:
// declare this method after `public slots:` in `.h` file void Persistance_Connect::reconnect() { socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); } void Persistance_Connect::onDisconnected() { qDebug() << "Disconnected! Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; QTimer::singleShot(0, this, &Persistance_Connect::reconnect); }
but frankly if you cannot even get a fresh socket to reconnect I have little hope....
-
@pingal said in Reconnecting using QAbstractSocket::connectToHost:
I've created socket2 for reconnection phase, same results.
That stumps me. If you can re-connect from a separate program but not from a brand new socket in the same program I don't know what to tell you. You can see from those links other people claimed to get it working.
The code you tried might better be, say:
// declare this method after `public slots:` in `.h` file void Persistance_Connect::reconnect() { socket.connectToHost(Server_Addr, Server_ConnectionPort, QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol); } void Persistance_Connect::onDisconnected() { qDebug() << "Disconnected! Trying to Reconnect to "<<Server_Addr<<":"<<Server_ConnectionPort; QTimer::singleShot(0, this, &Persistance_Connect::reconnect); }
but frankly if you cannot even get a fresh socket to reconnect I have little hope....
-
So now i placed the reconnect in onErr like below
void Persistance_Connect::onErr(QAbstractSocket::SocketError error) { switch (error) { case QAbstractSocket::AddressInUseError: qDebug()<< "SOCKET ERROR: Address is already in use"; break; case QAbstractSocket::ConnectionRefusedError: qDebug()<< "SOCKET ERROR: Connection refused"; break; case QAbstractSocket::HostNotFoundError: qDebug()<< "SOCKET ERROR: Host not found"; break; case QAbstractSocket::RemoteHostClosedError: qDebug()<< "SOCKET ERROR: Remote host closed"; break; } socket.disconnectFromHost(); QTimer::singleShot(0, this, &Persistance_Connect::reconnect); // Added here }
And removed the above from onDisconnect(). The module works fine now.
@JonB Thank you very much :)))
-
So now i placed the reconnect in onErr like below
void Persistance_Connect::onErr(QAbstractSocket::SocketError error) { switch (error) { case QAbstractSocket::AddressInUseError: qDebug()<< "SOCKET ERROR: Address is already in use"; break; case QAbstractSocket::ConnectionRefusedError: qDebug()<< "SOCKET ERROR: Connection refused"; break; case QAbstractSocket::HostNotFoundError: qDebug()<< "SOCKET ERROR: Host not found"; break; case QAbstractSocket::RemoteHostClosedError: qDebug()<< "SOCKET ERROR: Remote host closed"; break; } socket.disconnectFromHost(); QTimer::singleShot(0, this, &Persistance_Connect::reconnect); // Added here }
And removed the above from onDisconnect(). The module works fine now.
@JonB Thank you very much :)))
@pingal said in Reconnecting using QAbstractSocket::connectToHost:
The module works fine now.
Wow, that's great! (Still don't know why a
socket2
did not work, but never mind.)Like I suspected/wondered, the stackoverflow answers said that there is still some "clear up" which needs to be done after the
disconnectFromHost()
before a newconnectToHost()
will work on the socket, and that clear up needs to take place (somewhere/how) in the main event loop. Using aQTimer
to delay, even with just a delay of0
, allows the main event loop to be re-entered to do its magic before it executes thereconnect
.BTW, note how I (always) use New Signal Slot Syntax for my
connect()
s, never the old styleSIGNAL
/SLOT()
macros. This was actually introduced a long time ago at Qt5, but sadly many/most web examples still use the old syntax. The new one is much cleaner, and will pick up at compile-time whether the slot correctly matches the signal, instead of it failing (obscurely) at run-time. I suggest you always use the new style.