I have a QTcpSocket and I am reading into a loop. Each time a full packet has been read, or there has been an error, I manually check the status of the socket inside the loop, with:
while(true){
if(socket->state()==QAbstractSocket::ConnectedState){
qDebug()<
if(socket->waitForReadyRead(2000)){
//...
}
When I execute de program, once connected and the loop starts, it always prints qDebug()<
The problem is that disconnections are not detected. If I disconnect from network from the OS options, or even if I unplug the ethernet wire, it behaves the same: Socket state equals QAbstractSocket::ConnectedState, so it goes on, but without receiving anything of course.
I also tried to detect disconnections connecting disconnected() signal (after fist connection) to a reconnect function:
// Detect disconnection in order to reconnect
connect(socket, SIGNAL(disconnected()), this, SLOT(reconnect()));
void MyClass::reconnect(){
qDebug()<
panelGUI->mostrarValueOffline();
socket->close();
prepareSocket((Global::directionIPSerialServer).toLocal8Bit().data(), 8008, socket);
qDebug()<state();
}
But signal is never emited, because this code is never executed. Which is logical, since it looks like socket state is always ConnectedState.
If I plug again, connection is restored and starts to receive data again, but I do want to detect disconnections to show "Disconnected" at the GUI.
Why is QTcpSocket behaving this way, and how can I solve this problem?
EDIT: I'm creating socket at the class constructor, and then initialising calling prepareSocket function:
socket = new QTcpSocket();
socket->moveToThread(this);
bool prepareSocket(QString address, int port, QTcpSocket *socket) {
socket->connectToHost(address, port);
if(!socket->waitForConnected(2000)){
qDebug()<errorString();
sleep(1);
return false;
}
return true;
}
解决方案
Finally found the solution in this Qt forum:
If no data is exchanged for a certain while, TCP will start sending
keep-alive segments (basically, ACK segments with the acknowledgement
number set to the current sequence number less one). The other peer
then replies with another acknowledgement. If this acknowledgment is
not received within a certain number of probe segments, the connection
is automatically dropped. The little problem is that the kernel starts
sending keep-alive segments after 2 hours since when the connection
becomes idle! Therefore, you need to change this value (if your OS
allows that) or implement your own keep-alive mechanism in your
protocol (like many protocols do, e.g. SSH). Linux allows you to
change it using setsockopt:
int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
int maxIdle = 10; /* seconds */
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
int count = 3; // send up to 3 keepalive packets out, then disconnect if no response
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count));
int interval = 2; // send a keepalive packet out every 2 seconds (after the 5 second idle period)
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));