How to detect a TCP socket disconnection (with C Berkeley socket)

26,015

The only way you can detect that a socket is connected is by writing to it.

Getting a error on read()/recv() will indicate that the connection is broken, but not getting an error when reading doesn't mean that the connection is up.

You may be interested in reading this: http://lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html

In addition, using TCP Keep Alive may help distinguish between inactive and broken connections (by sending something at regular intervals even if there's no data to be sent by the application).

(EDIT: Removed incorrect sentence as pointed out by @Damon, thanks.)

Share:
26,015
Ayoub M.
Author by

Ayoub M.

Updated on August 08, 2022

Comments

  • Ayoub M.
    Ayoub M. almost 2 years

    I am using a loop to read message out from a c Berkeley socket but I am not able to detect when the socket is disconnected so I would accept a new connection. please help

    while(true) {
                bzero(buffer,256);
                n = read(newsockfd,buffer,255);
                printf("%s\n",buffer);        
    }
    
  • Damon
    Damon almost 13 years
    Slight correction: "Reading 0 bytes may also simply mean that the remote party didn't have anything to send, without it being a problem necessarily" -- receiving 0 bytes means that the other end performed a clean shutdown of the connection. If the other end did not have anything to send, you get EAGAIN or EWOULDBLOCK if the socket is non-blocking, or it blocks until data arrives. One way of detecting that the connection is down would be registering EPOLLHUP and EPOLLRDHUP on an epoll. This is not 100% reliable, but will report orderly shutdowns, half-shutdowns, and missing keepalives.
  • Damon
    Damon almost 13 years
    Of course a long, long, long time may pass before a broken connection is detected with keepalives. Alas, that's the nature of an independent-packet based network.
  • Pacerier
    Pacerier almost 12 years
    @Bruno The email you linked didn't explain why a successful read doesn't guarantee the connection is up.
  • Bruno
    Bruno almost 12 years
    @Pacerier, there's no difference between not getting anything because nothing was sent and not getting anything because the link is broken. (It's a general principle in fact. If you don't get any letter in the morning, either no one sent you anything or the postal system doesn't work: you can only find out which is the cause by trying to send something by post, more or less.) This is why you need to handle timeouts when using TCP connections. A connection that's closed abruptly will simply not send you anything to tell you its closing, because it can't.
  • Bruno
    Bruno almost 12 years
    This is also why most protocols implement delimiters or length headers when they write something, so that the reading party can know what to expect (e.g. Content-Length header on chunked transfer encoding in HTTP).
  • Pacerier
    Pacerier almost 12 years
    @Bruno I mean "why a successful read doesn't guarantee the connection is up?" If I received my letters successfully, then the postal system is up right?
  • Bruno
    Bruno almost 12 years
    @Pacerier, sure, a successful read with data will indeed tell you the connection is up, the problem is with a successful read that reads nothing (it also depends on whether you're blocking on read: you could block forever if you don't time out when nothing is read).
  • Pacerier
    Pacerier almost 12 years
    @Bruno sry I'm not quite sure what do you mean by "a successful read that reads nothing"? How can a successful read read nothing?
  • Bruno
    Bruno almost 12 years
    @Pacerier, if you're not blocking or if there's a timeout (in which case you might attempt to read again): the connection may still be up without the remote party sending any data. This is quite common.
  • jean
    jean almost 10 years
    write to the socket may be wait long time to get a error due to the sending buffer. If your package is very small, most of time it won't work
  • Bruno
    Bruno almost 10 years
    @jean, sure there may be a delay, but that's the only way to detect a disconnection, still. Flush the buffer if you need to know as soon as possible. (If you're waiting for read error, you can wait for a really long time... and that wouldn't be reliable.)
  • jean
    jean almost 10 years
    I am using boost.asio on android, I use async_write to get the disconnect error, but I found more than 50% there is nothing happen after connection closed even waiting two minutes. So I found stackoverflow.com/a/2939077 and boost.2283326.n4.nabble.com/… and something else, all they say use read. So...
  • Bruno
    Bruno almost 10 years
    @jean, with an async write, sure, you may have to wait. Using read to detect disconnection can only work for clean disconnections, not for abrupt ones. It's a TCP thing, nothing to do with Boost or other library. The answer you link to doesn't contradict this ("If the connection has went through an orderly shutdown [...] and [...]as long as the FIN packet from the client has arrived"). In general, to handle that sort of problems, you'd want your application to use and handle timeouts on read. (+ this question is about Berkeley sockets anyway).
  • jean
    jean almost 10 years
    If it is a abrupt disconnection, using write also helpless, right? That needs heartbeat to detect. I let client send heartbeat package every 15 secs, if there is no package arrive longer than 20 secs in server , it disconnect the connection. I use return value of write to detect the disconnect in client. But I found sometimes it not work even I want minutes(many package sent during this time). So I think you said:"detect that a socket is connected is by writing to it" is problematic.
  • Bruno
    Bruno almost 10 years
    @jean "If it is a abrupt disconnection, using write also helpless, right?" No, it's not helpless, it should fail, hence you can detect a disconnection. Your idea of expecting to receive a heartbeat every 15 sec is different, there might be a longer delay without the connection being close. You're then making an arbitrary decision regarding what delay you find acceptable, that's it (and this is often the right thing to do practically), but that doesn't actually tell you whether the socket was disconnected, it just means you give up and assume it has.
  • jean
    jean almost 10 years
    But it have not fail in my test. Nothing happen when write to a disconnected connection. Instead, use read works. And I don't know what's your definition of abrupt disconnection, I understand it by: unplug network wire, remote machine losing power... It couldn't detect by tcp itself.
  • Bruno
    Bruno almost 10 years
    @jean, yes, abrupt in that sense (complete packet loss without warning). When nothing is meant to be sent, you can't know whether you're meant to receive something (hence the idea of hearbeat in the protocol as you suggested, for protocols that support that). The only way to find out whether it's disconnected is to try to write. Trying to read something whether you don't know whether it's meant to have sent anything won't tell you anything either way. Your case is different since you're using an async write. I don't know boost.asio very well, but try to flush the buffer immediately if you can.
  • Bruno
    Bruno almost 10 years
    "It couldn't detect by tcp itself.": without TCP keepalives (which are a form of writing), no. Once the connection is established, if you don't know whether the remote party is meant to have sent something, and if you try to read and get nothing, you'll just get nothing indeed. A connection that is abruptly terminated in a way its FIN doesn't go across will just look like an established connection.
  • jean
    jean almost 10 years
    I don't understand: "When nothing is meant to be sent, you can't know whether you're meant to receive something". I can simply do: while(1) asyncread(). when it return error, I know disconnected. flush buffer should work, but it is a feature of os driver, it is inaccessible.
  • Bruno
    Bruno almost 10 years
    @jean No, you can't, that's the point. Check the TCP flow diagram. If you've established a connection and you don't receive anything at all, then you won't know whether (a) the cable was cut (whether or not the other side tried to close the connection by sending FIN) or (b) the other side simply didn't have anything to send. If the connection is established and if you don't know whether to expect to receive anything (you expect the connection to be up a priori), then you can't know by just reading.
  • jean
    jean almost 10 years
    OK, I got you. I want know what happens write into a connection which is a abrupt disconnection? You said it should fail, because the remote point is unreachable and device like router, switch will detect this and let tcp know this and finally report back to sender?
  • user207421
    user207421 about 7 years
    No it isn't. It is because he fails to check for either an error or even end of stream. He is totally ignoring the result returned by reD().