28

I have an application which needs to send some data to a server at some time. The easy way would be to close the connection and then open it again when I want to send something. But I want to keep the connection open so when I want to send data, I first check the connection using this function:

bool is_connected(int sock)
{
    unsigned char buf;
    int err = recv(sock,&buf,1,MSG_PEEK);
    return err == -1 ? false : true;
}

The bad part is that this doesn't work. It hangs when there is no data to receive. What can I do? How can I check if the connection is still open?

iammilind
  • 68,093
  • 33
  • 169
  • 336
opc0de
  • 11,557
  • 14
  • 94
  • 187

3 Answers3

34

Don't check first and then send. It's wasted effort and won't work anyway -- the status can change between when you check and when you send. Just do what you want to do and handle the error if it fails.

To check status, use:

int error_code;
int error_code_size = sizeof(error_code);
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, &error_code, &error_code_size);
Aaron
  • 9,123
  • 5
  • 40
  • 38
David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • 2
    True... but sometimes it is useful to check if a socket is still connected. Setting it to non-block, and then reading with peek_msg is a good way to elicit an error code to check it the socket is still connected. – Rafael Baptista Jun 14 '13 at 13:21
  • 4
    @RafaelBaptista Why? *Using* it will check. Testing first cannot work reliably, for the reason David gives above. – user207421 Jul 30 '13 at 07:34
  • @EJP: I want to check client connection is alive so I don't waste resources in case it is not. – che Oct 24 '14 at 12:39
  • 12
    @che Right, so check by using it. Then if it's not alive, you can stop wasting resources. The check itself is a waste of resources. – David Schwartz Oct 25 '14 at 04:53
  • If you are monitoring connections, say for a clustered app, it can be nice to periodically test connections to ensure that any failover can be performed even when connections are not in use. That would be a decent reason to test a connection. – Seth Mar 29 '17 at 19:12
  • 5
    @seth Which you do by *using* it. – David Schwartz Apr 01 '17 at 16:52
  • 2
    There is 100% use cases for checking a connection state - just not as a pre-send routine as already stated. Sometimes you need to know the second a connection is lost in order to report to users - not only when a send fails – Danaldo Dec 08 '22 at 14:55
  • @Danaldo I don't agree. If you need to know the second a connection fails, you need to do a send. Doing a send is the only reliable way to tell if a TCP connection has failed. And if the connection has failed, the send will fail. – David Schwartz Dec 08 '22 at 17:57
  • 1
    We have customers that want to know as soon as a connection fails - ie if someone has kicked an ethernet cable out. They dont want to run a process that takes significant time to get to the end and then the final send via tcp fails because it cant do the send. Granted checking in advance doesnt guarantee that a time t later its stable - but it does mean you can possibly prevent a lot of wasted time. Even more so if you check during the process on each step that its still possible. It depends what you use TCP for as to the benefits. For a lot of use cases theres no point checking; but not all. – Danaldo Dec 08 '22 at 18:19
13

You need to enable non-blocking behavior, by setting O_NONBLOCK using fcntl. One easy but non-standard way to do a non-blocking read would be to use:

recv(sock, &buf, 1, MSG_PEEK | MSG_DONTWAIT);

Afterwards, you must check errno if it fails. It can fail with EAGAIN or it can fail with EBADF or ENOTCONN etc.


Obviously, the simplest and cleanest way to deal with this would be to avoid "forgetting" if the socket is connected or not. You'll notice if the socket becomes disconnected once a recv returns 0 or a send returns EPIPE.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • 3
    This won't detect all connection failures. Only a send() can do that. – user207421 Sep 13 '12 at 21:44
  • 1
    @EJP That's true in fact. I was just improving the solution of the op. What you are suggesting is the only bullet-proof solution, but it entails sending. – cnicutar Sep 14 '12 at 06:17
  • Also, it is worth mentioning here that since we are using MSG_DONTWAIT flag, we do not need a separate fcntl() syscall to mark socket non-blocking via O_NONBLOCK: MSG_DONTWAIT makes socket non-blocking here. – avernus Aug 24 '21 at 11:42
5

Default use of TCP doesn't allow very timely detection of dead sockets (outside of normal closure) so I'll suggest that an "is_connected" function like this is largely useless for all practical purposes. Consider implementing an application-layer keep-alive and track if it's alive based on timely responses (or lack thereof).

edit: after posting i see BoBTFish's link, which is effectively the same thing.

mark
  • 5,269
  • 2
  • 21
  • 34