Reputation: 33
I have a tcp link with server by socket on linux. And I used select() function to monitor if there is data, if there have, I use recv to get the data.
Now I want to know if network is broken(such as cable was removed). But I can't get the exception even I monitor the exception.
FD_SET( m_socket, &except_fds );
int result = select( m_socket + 1, &fds, 0, &except_fds, timeout == -1 ? 0 : &tv );
What confused me is there is similar implementation (java.net.socket) on android, I can catch exception immediately if I set the phone to flight mode.
Is select() implementation platform specific?
In short, if this method can be used to monitor the network broken? if not, is there any solution for this?
Upvotes: 1
Views: 1265
Reputation: 28872
select
will return if an error is reported on any of the file descriptors that select
is monitoring.
For a socket, and error will be reported if the OS loses connection to the local link-layer network. This means that select
will return if the host loses network connectivity entirely. This happens when your internet cable is unplugged or your mobile is switched to flight mode.
TCP however has not way of knowing whether the remote host is reachable or not so if however a remote router goes down or the remote host disappears. You are unlikely to receive an error especially when you are not actively communicating with the remote host, so until your connection times out, you will be unaware of any problems.
Upvotes: -1
Reputation: 54325
If you want to detect changes in network conditions you will need to use specific system services.
At a low level you can detect the hot plug or remove of network devices with rules in udev. Higher up are services like NetworkManager, which will communicate on DBUS. You can subscribe to it to get notified of network changes.
If you aren't using NetworkManager then it depends on your system scripts. Some have ifdown-post and ifdown-local. Others have scripts you can run in response to DHCP events, which includes network unplug. Others have programs you can run to monitor the network plug state such as ifplug or ifplugd or netplugd.
If you want the kernel to notify you directly instead of using a system service or daemon I think you'll need to get into using the netlink protocol to scan the available network devices.
Upvotes: 1
Reputation: 182753
There was nothing special you needed to do. Loss of a TCP connection, whether due to the other end closing it or due to an error, is not exceptional. You were already waiting for the socket to be readable, and if the connection closes or errors, your wait is over. Your code should already try to read from the socket when the wait is over, so it should detect the situation already.
Note that on most platforms, the temporary loss of connectivity will not close TCP connections. This would be extremely annoying in conditions of temporary connectivity loss. In fact, in the old days, there were systems that had long-lived TCP connections but only had network connectivity when there was activity. The connections remained alive even while the network connection was intentionally disabled. This behavior is by design.
The most reliable way to detect if a TCP link is still usable is to send data on it. If the other end of the link is not able to acknowledge the data, the send will eventually time out. (Your call to the send function may have already returned success, but the timeout will trigger an error that will make the socket readable. When you call a read function, the error will be reported to you.)
Upvotes: 1
Reputation: 3917
The way the TCP protocol generally works, an error is such that data fails to be transmitted (isn't ACK
'd). Unless data fails to be transmitted, there is no error.
So, you can periodically send small packets to detect dropped connections either using setsockopt
SO_KEEPALIVE
, or define a simple heartbeat protocol. You can also override the keepalive defaults using TCP_KEEPCNT
, TCP_KEEPIDLE
, and TCP_KEEPINTVL
.
Upvotes: 3
Reputation: 647
You may need to set the socket to use keep alive in order for it to be able to detect if the connection has been broken. You will need to use setsocketopt()
with SO_KEEPALIVE
as the third argument. Try checking this out.
Upvotes: 0
Reputation: 310859
What confused me is there is similar implementation (
java.net.Socket
) on android, I can catch exception immediately if I set the phone to flight mode.
Not so similar. java.net.Socket
does not use select()
, except for read timeouts on platforms that don't support SO_RCVTIMEO
.
Is
select()
implementation platform specific?
Of course.
In short, if this method can be used to monitor the network broken?
No.
if not, is there any solution for this?
The only way you can reliably detect a broken TCP connection is to try to write to it. Eventually, after taking into account buffering and retries, write()
or send()
and friends will return -1 with errno == ECONNRESET
.
Upvotes: 1