QTcpSocket && check cable disconnected
-
Hi all,
I have 2 applications, a tcpServer and a tcpClient.
The client connect to the server and some times receive a string from server a string.
When the client receive a string it doesn't answer nothing.
If the client crash or exit I know from the server that the connection is disconnected checking QTcpSocket::state() .My problem is that if I disconnect the ethernet cable from the client, the socketState is always "connected" .
Is there a solution?
-
That is the expected behaviour.
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(2):
@
int maxIdle = 30; /* seconds */
int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
@ -
You can also use" Qt Mobility's QSystemNetworkInfo ":http://doc.qt.nokia.com/qtmobility-1.0/qsystemnetworkinfo.htmlto receive signals as to changes in the network. Of course this is a one sided affair as the client or server can only get info as to their own network status. You could have the client ping the server every minute when there is no data is to be sent. Then instruct the server to tear down the connection if no ping received for a certain period. Of course you could also work it vice versa and have the server ping the client every minute
-
If you just want to check if the ethernet cable is connected or not you can check the network interface flags with "QNetworkInterface::flags()":http://doc.qt.nokia.com//4.7/qnetworkinterface.html#flags. Look into "QNetworkInterface::InterfaceFlag":http://doc.qt.nokia.com//4.7/qnetworkinterface.html#InterfaceFlag-enum . If the flag QNetworkInterface::IsUp is not set the cable is not connected to an active network.
-
[quote author="Andreas Bacher" date="1292397533"]If you just want to check if the ethernet cable is connected or not you can check the network interface flags with "QNetworkInterface::flags()":http://doc.qt.nokia.com//4.7/qnetworkinterface.html#flags. Look into "QNetworkInterface::InterfaceFlag":http://doc.qt.nokia.com//4.7/qnetworkinterface.html#InterfaceFlag-enum . If the flag QNetworkInterface::IsUp is not set the cable is not connected to an active network.[/quote]
Watch out, QNetworkInterface will simply query the system about the status of its interfaces. On Linux I can bring up an ethernet interface even if it's not plugged in! The flag that here does the job is "IsRunning".
@
#include <QtNetwork>
#include <QtDebug>int main()
{
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
foreach(const QNetworkInterface & interface, interfaces)
{
if (interface.flags() & QNetworkInterface::IsUp)
qDebug() << interface.name() << interface.flags();
}
}
@Output:
@
"lo" QFlags(0x1|0x2|0x8)
"eth0" QFlags(0x1|0x4|0x20)
"wlan0" QFlags(0x1|0x2|0x4|0x20)
@Even with eth0 unplugged:
@
$ ip link show eth0
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
link/ether 00:16:b0:11:45:aa brd ff:ff:ff:ff:ff:ff
@As you can see, the eth0 is missing the 0x2 flag.
-
[quote author="peppe" date="1292362602"]That is the expected behaviour.
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(2):
@
int maxIdle = 30; /* seconds */
int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
@[/quote]
2 hours!!!
My application works on Linux so today I'll try your solution, thanks.
[quote author="DBoosalis" date="1292376791"]You can also use" Qt Mobility's QSystemNetworkInfo ":http://doc.qt.nokia.com/qtmobility-1.0/qsystemnetworkinfo.htmlto receive signals as to changes in the network. Of course this is a one sided affair as the client or server can only get info as to their own network status. You could have the client ping the server every minute when there is no data is to be sent. Then instruct the server to tear down the connection if no ping received for a certain period. Of course you could also work it vice versa and have the server ping the client every minute
[/quote]
I compiled Qt from source without Qt Mobility so I'd like to avoid it.
[quote author="Andreas Bacher" date="1292397533"]If you just want to check if the ethernet cable is connected or not you can check the network interface flags with "QNetworkInterface::flags()":http://doc.qt.nokia.com//4.7/qnetworkinterface.html#flags. Look into "QNetworkInterface::InterfaceFlag":http://doc.qt.nokia.com//4.7/qnetworkinterface.html#InterfaceFlag-enum . If the flag QNetworkInterface::IsUp is not set the cable is not connected to an active network.[/quote]
Thanks, I didn't consider your solution and it seems interesting. But this way if I disconnect the net cable in the client I can only check the event in the client end not in the server.
-
[quote author="Luca" date="1292399395"]
[quote author="peppe" date="1292362602"]That is the expected behaviour.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(2):
@
int maxIdle = 30; /* seconds */
int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
@[/quote]
2 hours!!!
My application works on Linux so today I'll try your solution, thanks.
[/quote]I forgot to say that it's really Linux specific (not unix!), thus not portable at all, and you should also take a look to the TCP_KEEPCNT / TCP_KEEPINTVL sockopts, which respectively are the total number of probes sent (without any response) before dropping the connection and the interval between them. The manual page tcp(7) explain them in detail. For reference read of course ip(7), socket(7) and setsockopt(2).
All in all, I'd simply implement a keepalive mechanism by having the server and the client exchange 1 byte of traffic if the connection is idle for a certain while. If nothing is received within a configurable interval, break the connection. This
works;
is portable.
:-)
-
Thanks again peppe,
I finally used your solution and it works as expected.The code I used is:
@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));
@I only must fine tune the values maxIdle, count and interval.
-
[quote author="Luca" date="1292402275"]Thanks again peppe,
I finally used your solution and it works as expected.
[/quote]Glad to hear that :-)
[quote]
The code I used is:
@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));
@I only must fine tune the values maxIdle, count and interval.[/quote]
<nitpick mode=on>
Use IPPROTO_TCP everywhere, not SOL_TCP.
</nitpick>