How can I tell if my socket's peer closes the socket?

Article ID: 1083
Last updated: 05 Feb, 2008
Article ID: 1083
Last updated: 05 Feb, 2008
Revision: 1
Views: 11445
Posted: 27 May, 1998
by Dean J.
Updated: 05 Feb, 2008
by Dean J.
Problem


I'm using RWSocket or RWSocketPortal low-level operations like recv() and send(), and would like to know how to determine if the other side of my socket closes (i.e. if the peer closes the socket).


Cause


For a number of reasons, it is difficult to determine the status of a TCP/IP socket at the other end of the socket. TCP/IP (unless special options like SO_KEEPALIVE are used) does not send any 'watchdog' or 'heartbeat' data from peer-to-peer to make sure the the socket is still considered open by both parties. This makes it fundamentally difficult to detect closure. For example, with normal sockets, if one side of the connection involuntarily stops talking on the socket altogether (i.e. it's power is disconnected), it is not possible for the other side of the connection to know about this (unless logic is written by the programmer to poll the other side to make sure it is alive). However, when sockets are shut down properly, it is possible to determine that they have closed.


Action


With Tools.h++ Professional's version of the recv() and send() calls, it is quite easy to determine when your peer closes the socket. There are two ways that you can receive the notification, either through an EOF when reading if the peer closes the socket properly, or, for all other cases, a socket exception if the other side aborts the connection. (UNIX users may also get a SIGPIPE from their operating system, however, this is highly dependant on the IPC implementation in you OS's kernel and networking components, see the documentation that came with your OS for details on this.) Note also that the code below will work with both blocking and non-blocking sockets.

To check for an EOF when reading with the recv() call, use the alternate forms of the recv() call that allow you to get a RWNetBuf or RWNetBuf::State from the recv() call, for example, instead of:

RWCString buffer;
buffer = mySocket.recv();
, use this:
RWNetBuf buffer;
buffer = mySocket.recv();

An RWNetBuf contains both an RWCString which contains the data, and a state which tells you if the other side has closed or not. You can test this by treating the RWNetBuf like a boolean, and you can retrieve the data from it by treating it like an RWCString:

if(buffer) {
std::cout << The socket is still open, and I got << (RWCString)buffer << from it! << endl;
} else {
std::cout << The peer closed the socket! << endl;
}

The other way that socket closure may be propagted to you is by an exception. Calls such as recv(), send(), and others will throw an exception if the socket reports an error, and this is what can happen if the other side closes the socket improperly. Check for it using C++'s try-catch mechanism:

RWSocketPortal sp = ...
...
try {
sp.send(Hello out there!);
} catch (RWxmsg &x) {
cout << Error occured while sending: << x.why() << endl;
}
This code will catch an exception if the peer closes before/during the send().

Also, if you use the select() call provided by Net.h++, and one of the sockets on which you are select()'ing is closed, select() immeaditely returns the RWSocketAttribute for that socket in the list, with it's sock_attr_canread and sock_attr_canaccept (CANREAD and CANACCEPT in previous versions) flags set. Use the variations of the recv() and send() methods described above to read or write to the socket and determine if there is data present or if the socket is closed.

This article was:   Helpful | Not helpful
Report an issue
Article ID: 1083
Last updated: 05 Feb, 2008
Revision: 1
Views: 11445
Posted: 27 May, 1998 by Dean J.
Updated: 05 Feb, 2008 by Dean J.
Also listed in


Others in this category