QTcpSocket state always connected
-
I'm using Qt 5.5 on Ubuntu 32 Bit.
Unfortunately I can't upgrade to 64 Bit and 5.9.
This a little example// Open m_pTcpSocket = new QTcpSocket(); m_pTcpSocket->connectToHost(strIP,uiPort); if(!m_pTcpSocket->waitForConnected(lTimeout)) {// Error Close(); } // Check if (m_pTcpSocket->state() == QAbstractSocket::ConnectedState) { return bConnected; }
-
@Gianluca86
and how are you checking if you stay connected?
I mean the condition which leads you to "stays always connected". -
Sorry, I forgot the else:
// Check if (m_pTcpSocket->state() == QAbstractSocket::ConnectedState) { return bConnected; } else {// Do other stuff }
and I insert before the If
qDebug()<<m_pTcpSocket->state();
-
@Gianluca86 said in QTcpSocket state always connected:
If the server disconnects or I unplug the ethernet cable, the status remains "Connected".
i still don't see any code where you would (dynamically) react on such event?!
Or where do you assume in your code that to happen? -
@raven-worx :
I didn't write all the code, however I always call the function that contains the check if, what I wrote before.@VRonin :
I can't, I have a error. -
@Gianluca86 said in QTcpSocket state always connected:
@raven-worx :
I didn't write all the code, however I always call the function that contains the check if, what I wrote before.@VRonin :
I can't, I have a error.Do you really expect help with such horrible replies?
You simply hide code, you just say you have an error, but dont even tell with one .... seriously? -
-
@raven-worx :
The error does not depend on my code.
It is simply the Socket that returns the Connected state.
As I said, I call the IF, nothing else. There is no other code I need to show.@VRonin :
warning: lambda expressions only available with -std=c++11 or -std=gnu++11 [enabled by default]
QObject::connect(m_pTcpSocket,&QAbstractSocket::disconnected,->void{qDebug("Disconnected");});
^ -
@Gianluca86 said in QTcpSocket state always connected:
lambda expressions only available with -std=c++11 or -std=gnu++11 [enabled by default]
add
CONFIG += c++11
to your .pro file and re-run qmake to fix this or just create aQ_SLOT void logDisconnect(){qDebug("Disconnected");}
and connect to that instead of the lambda -
It prints the disconnection message. But the state doesn't change.
I think I'll give up, I'll use the Send and Receive timeout to check the connection. Thanks for the help. -
@Gianluca86 said in QTcpSocket state always connected:
It prints the disconnection message. But the state doesn't change.
Since you said you do not need to post more code, i tell you it's impossible to achieve what you want with the code you've posted so far.
I also do not know how you are checking the state. Obviously the code you've posted only checks the state once. And thats right after a connection happened...So what do you actually expect?
-
After the connection, I call the function with the check state every 3 seconds, with a timer.
I don't do anything special, I simply create a Socket, connect and check state, nothing more.
So I would expect that if the server program to which I was connected closes, the state of my tcpsocket changes, but unfortunately it doesn't happen, so I'll have to use another method to know if the connection is active.thanks anyway
-
@Gianluca86 said in QTcpSocket state always connected:
But the state doesn't change.
Pretty sure it does https://code.woboq.org/qt5/qtbase/src/network/socket/qabstractsocket.cpp.html#2788
In fact you can connect to
stateChanged
signal to check that -
Hi everyone.
Topic is old, but problem still exists. I'm using QT 5.14.1 on Windows 7 and tried to compile project with MinGW(32/64) and MSVC17(32/64), but results are same: socket does not react on physical disconnect.
It is important remark that I can't use blocking calls (like waitForBytesWritten() / waitForConnected() / etc) in my project.First I used next check (I think TS talked about something like this):
bool IsConnected() { return socket_.state() == QTcpSocket::ConnectedState; } //---- somewhere in code ----- if(IsConnected()) { // do something; } else { /*error occured*/ }
And I got same result: if wire was plugged out after connection state still was ::ConnectedState. Next I tried to use socket signals:
connect(&socket_, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(sockStateChanged(QAbstractSocket::SocketState))); connect(&socket_, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sockErrorOccured(QAbstractSocket::SocketError)));
sockStateChanged() and sockErrorOccured() only send messages to debug output with text from error list and states.
They work fine during connection saying what is happening with socket:// if wire is plugged in State changed: "The socket is performing a host name lookup." State changed: "The socket has started establishing a connection." State changed: "connection is established." // if not State changed: "The socket is performing a host name lookup." State changed: "The socket has started establishing a connection." State changed: "The socket is not connected." Socket error occured: "An error occurred with the network (e.g., the network cable was accidentally plugged out)."
But when connection established they just stop working. If I plug out wire no signals would be emitted and state would not change (still ConnectedState). Even if I try to send something, there is no reaction (see UPD). If I plug wire back nothing happens (board/server will not receive/send data, no signals emitted).
I tried to use VRonin method too, but it does not work (no disconnected() signal).QObject::connect(&socket_, &QAbstractSocket::disconnected, []()->void{qDebug("Disconnected");});
After all only one solution seems to work for me: use timer to wait response and disconnect if there is nothing to read.
// timer as class member QTimer readTimer; int readTimeout; //----------------------- void configureTimer() { // configuring & connection to slot readReply() readTimer.setSingleShot(true); readTimer.setInterval(readTimeout); connect(&readTimer, SIGNAL(timeout()), this, SLOT(readReply())); } //----------------------- void sendRequest() { if (socket_.write(pingRequest_) == -1) { // result is always 0 after connection, so we would not get here qDebug() << "Request: sending failed"; return; } // timer will call readReply after waiting readTimer.start(); } //----------------------- void readReply() { if (socket_.bytesAvailable() == 0 || !isConnected()) { qDebug() << "No bytes available or disconnected"); // call reconnect return; } QByteArray reply = socket_.readAll(); //do something with reply }
UPD:
I found out that if you try to send data when wire is out after a ~20 sec timeout socket will close emitting all necessary signals.
But it will stay Connected if you don't. I waited for several minutes and state was not changed.So you should send "ping" sometimes to know about disconnect in case if your application doesn't send data often. If your ping waits reply you can close socket by timeout, if not - wait for automatic closing.
-
@puzzled_giraffe If you want your TCP socket to fast detect connection with counterpart is lost, you have to set KeepAliveOption. On Windows systems, you have to do this before connecting the socket.
auto mySocket = new QTcpSocket(); mySocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); mySocket->connectToHost(...);
-
@KroMignon I googled it a bit and found that this option only enables "keep alive" mode on socket. Windows has a 2 hours default delay before first request, so it is not very useful if someone wants to get actual connection state.
So we return to "heartbit ping", OS registry changing (to reduce default intervals) or low level socket configuring.I tried it in a code, so yes, it does not have an noticable effect without additional actions.
-
@puzzled_giraffe said in QTcpSocket state always connected:
I tried it in a code, so yes, it does not have an effect without additional actions.
By googling in found this:
The SO_KEEPALIVE socket option is valid only for protocols that support the notion of keep-alive (connection-oriented protocols). For TCP, the default keep-alive timeout is 2 hours and the keep-alive interval is 1 second. The default number of keep-alive probes varies based on the version of Windows.
So for Windows, you can setup those settings like this:
int fd = mySocket->socketDescriptor(); int enableKeepAlive = 1; int maxIdle = 10; int count = 3; int interval = 2; int result; result = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive)); result = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle)); result = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count)); result = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
Take a look at https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt for more details.
-
@puzzled_giraffe , @KroMignon
I will just throw in an observation based on my tests years ago. Please take what I say with a pinch of salt, I might be wrong, @KroMignon may know more than I do, but....When I tried this out (under Windows) on a product we developed I actually found that the keep-alive stuff made the situation worse. Because it's testing all the time, I found that it actually noticed missing connections and dropped/closed them more than if I had nothing and left TCP to its own devices.
So do you really need to be heartbeat pinging?
-
@KroMignon said in QTcpSocket state always connected:
result = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
result = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
result = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count));
result = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));TCP_KEEPIDLE / TCP_KEEPCNT / TCP_KEEPINTVL - linux options, aren't they?
So for windows I found next solution:
add this lib to your project *.pro fileLIBS += -lws2_32
Next after socket connection you should use:
#include <Ws2tcpip.h> //------ // socket is QTcpSocket* if (socket->state() == QAbstractSocket::ConnectedState) { int fd = socket->socketDescriptor(); DWORD dwBytesRet = 0; struct tcp_keepalive alive; // your options for "keepalive" mode alive.onoff = TRUE; // turn it on alive.keepalivetime = 30000; // delay (ms) between requests, here is 30s, default is 2h (7200000) alive.keepaliveinterval = 5000; // delay between "emergency" ping requests, their number (6) is not configurable /* So with this config socket will send keepalive requests every 30 seconds after last data transaction when everything is ok. If there is no reply (wire plugged out) it'll send 6 requests with 5s delay between them and then close. As a result we will get disconnect after approximately 1 min timeout. */ if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0, &dwBytesRet, NULL, NULL) == SOCKET_ERROR) { QDebug() << "WSAIotcl(SIO_KEEPALIVE_VALS) failed with err#" << WSAGetLastError(); return; } }