22

I am having an application which established a socket connection on a port number 5005 with another device(hardware device with a web server).

Now if my hardware device disconnects then i loose connection with the device.

  1. Does this mean that the socket i was using until now becomes invalid.

  2. Do i get any special message like null character or something when this disconnect happens.

  3. If the socket connection i was having became invalid then why doesnt the recv() socket function throw and SOCKET_ERROR. Instead why do i receive data of 0 length.

Thanks

user207421
  • 305,947
  • 44
  • 307
  • 483
ckv
  • 10,539
  • 20
  • 100
  • 144
  • Have you called shutdown() on the remote side? This will make recv return 0: http://stackoverflow.com/questions/2843277/c-winsock-p2p/2920787#2920787 – default Jun 22 '10 at 07:49
  • @Default On most platforms, closing a socket descriptor/handle will perform an implicit shutdown if one has not already been performed. – Remy Lebeau Jul 29 '20 at 20:47

8 Answers8

40

When recv returns a value of 0 that means the connection has been closed.

See the recv man page:

These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown.

In answer to question #1, yes the socket is now invalid. You must create a new socket and connection for further communications.

Edit

Now as valdo pointed out below, there is also the possibility of having a half-closed TCP connection in which you can't receive any more but you can keep writing to the socket until you've finished sending your data. See this article for more details: TCP Half-Close. It doesn't sound like you have this situation though.

In answer to question #2, there are basically two ways to detect a closed socket. This assumes that the socket went through an orderly shutdown, meaning the peer called either shutdown or close.

The first method is to read from the socket in which case you get a return value of 0. The other method is to write to the socket, which will cause the SIG_PIPE signal to be thrown indicating a broken pipe.

In order to avoid the signal, you can set the MSG_NOSIGNAL socket option in which case send would return -1 and set errno to EPIPE.

Robert S. Barnes
  • 39,711
  • 30
  • 131
  • 179
  • So what i need to do is if i get a return value of 0 then i need to close that socket and open another socket right? – ckv Jun 22 '10 at 07:20
  • 4
    @ckv there is actually one more possibility for the `recv()` to return zero. It does that when the size of bytes to receive is zero. I just occasionally walked through these rakes — long time couldn't figure out, why the socket is okay, but I keep getting zero ☺ – Hi-Angel Apr 29 '15 at 15:31
  • 1
    @Hi-Angel Perhaps you've set up non-blocking mode? – Little Helper Oct 25 '15 at 12:48
  • @LittleHelper I don't remember, but I don't think that does matter. See: the successful call returns a number of bytes received. You asked to receive zero bytes, so it checks whether there's a need to get more bytes from a socket *(there isn't, all the «zero» bytes were got)*, and returns the number it received — that is, zero. – Hi-Angel Oct 25 '15 at 13:40
  • @LittleHelper No. You only get zero if (a) you specified a zero length or (b) the peer has disconnected. If there is no data available in non-blocking mode you get -1 with `errno == EAGAIN/EWOULDBLOCK`. – user207421 Jun 27 '18 at 02:28
  • NB The socket isn't invalid, but it's useless. You can keep calling `recv()` with it, for example, but you will just get more zeros. – user207421 Oct 11 '19 at 18:54
12

Agree with Robert S. Barnes. Except the claim that the socket is now "invalid".

It's still valid. You can use it. You can even send data to the peer. The only thing you can't do with it is call recv.

valdo
  • 12,632
  • 2
  • 37
  • 67
  • 2
    +1 Right, I forgot about the possibility of a half-close. I'll update my answer. – Robert S. Barnes Jun 22 '10 at 08:12
  • Wanted to point out that this depends on whether or not the peer called `close`, or did a half-close by calling `shutdown` with the `SHUT_WR` flag. See the `shutdown` manpage: http://www.kernel.org/doc/man-pages/online/pages/man2/shutdown.2.html – Robert S. Barnes Jun 23 '10 at 06:45
  • Well, you *can* call `recv()`, but all you will get is another zero. – user207421 Jun 26 '18 at 01:35
3

If recv returns 0 this means that the peer has closed the socket.

recv won't throw because its a C function.

If there's an error recv will return -1. In which case your application has to check the type of error. Note that a return of -1 does not imply that the peer has closed its socket.

user207421
  • 305,947
  • 44
  • 307
  • 483
sashang
  • 11,704
  • 6
  • 44
  • 58
3

To correct numerous misstatements in the existing answers:

  1. Does this mean that the socket i was using until now becomes invalid.

No. It means the peer has closed the connection, or shut it down for output from his end. Your socket is still valid. You can call recv() again, but all you will get is another zero. You can call send() on it too, and if the peer has only shutdown the connection for output the data will be sent.

  1. Do I get any special message like null character or something when this disconnect happens.

No, you get zero return value from recv(). That's what it's for. It is delivered out-of-band, not in the data buffer.

  1. If the socket connection i was having became invalid then why doesnt the recv() socket function throw

Because it's a C API, and there are no throws in C, or in Unix system calls either.

and SOCKET_ERROR.

Because it isn't an error.

Instead why do i receive data of 0 length.

You don't 'receive data of 0 length'. You receive a return value of zero instead of data.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • This has nothing to do with OOB-Data. This is something completely different. You get this return value if the receiving side receives a `FIN` packet. OOB-Data describe packets which are marked as URGENT through the TCP-Urgent flag. (That's the way posix systems interpret the urgent flag). – Sebi2020 Oct 01 '20 at 14:43
  • @Sebi2020 I didn't say anything about OOB-data. I said the end of stream inidicated is delivered out of band, as a return value, rather than in the data buffer, which would be in-band. – user207421 Mar 29 '21 at 22:31
2

I suppose you're using TCP to communicate with your device.

  1. The socket itself is still "valid", however the the connection was lost.

  2. You get a return value of 0 for recv() when the connection was closed by the other host (wether this disconnection was graceful or not doesn't matter)

  3. socket functions are like C functions: they don't throw because they can be used in C programs, where exceptions do not exist.

ereOn
  • 53,676
  • 39
  • 161
  • 238
1

Given that you're talking to a web server, I'll assume you're using TCP sockets.

To answer:

  1. Sockets don't become invalid due to a disconnect; they simply go into a disconnected state. It's still safe to call socket operations on them.

  2. You don't get any special messages when the disconnect occurs. If you call recv() in a blocking fashion, it will return when disconnected, and the number of bytes returned from the call won't match the number of bytes you asked for.

  3. There isn't really an answer to this - it's how the socket API was implemented originally, and we're stuck with that implementation as everyone implements Berkley Sockets.

Blair Holloway
  • 15,969
  • 2
  • 29
  • 28
  • 2
    The number of bytes returned hardly ever matches the number you asked for. This does not signal end of stream. Zero is the signal for that. – user207421 Jun 27 '18 at 02:26
-1

Nearly all apps that I'm familiar with use blocking calls only. You only read the socket when select()/epoll() tell you that it is readable. When it's readable, and you read it and recv 0 bytes, then you know to close it.

  • 2
    "*You only read the socket when select()/epoll() tell you that it is readable*" - or, you simply let `recv()` block until data arrives or the connection is closed/errors. `select()`/`epoll()` is typically used only when you want to *multiplex* with other things at the same time that you are reading from the socket. – Remy Lebeau Jul 29 '20 at 20:55
  • Additional notes to @RemyLebeau comment. You can use threads to handle multiple connections. In this case you would use blocking calls. If you have only one thread handling connections you can use`select()/epoll()` to do "multiplexed reads/writes". If you don't want to use select/epoll you could use non-blocking recv/send calls to handle multiple connection within one thread. – Sebi2020 Oct 01 '20 at 14:34
-2

If you have set the socket as non-blocking, at least using winsock2, you will get 0 when there is no data to receive, regardless of whether there is an application on the other end of the socket and I've also seen this where the other end has shutdown the socket. recv returns 0, WSAGetLastError() returns 0 but /nothing/ is on the other end. I actually came here to find out how you detect that there is nothing on the other end.

  • 1
    "*If you have set the socket as non-blocking, at least using winsock2, you will get 0 when there is no data to receive*" - that is not true. In that situation, `recv()` will return `SOCKET_ERROR` (`-1`) and `WSAGetLastError()` will return `WSAEWOULDBLOCK` (`10035`). `recv()` will return 0 only if the peer performed a *graceful shutdown* (sent a `FIN` packet), or the requested buffer size is 0 (which would be a coding bug, since TCP sockets can't send 0-length data). – Remy Lebeau Jul 29 '20 at 20:51