recv() returns 0
Asked Answered
A

3

8

I have a very annoying problem that I found several times on other forums but I can't find a proper solution. The problem is recv() returns 0 on the last few bytes of a connection. Here are some background information.

  • Both (client / server) applications run on the same machine.
  • Both (client / server) sockets are non-blocking
  • The transfered data size is 53 bytes.
  • Both (client / server) call shutdown and closesocket when the last send()/recv() was executed.
  • I also tried with SO_LINGER and 10 seconds, no success either

I call send() several times (small chunks) and from the client side 53 bytes are transfered. The server calls recv() several times (4 byte requests) and read 49 bytes and then returns 0 (54 Bytes - 49 Bytes, so 4 bytes are missing).

MSDN and some forums write for non-blocking sockets:

  • recv() definitely returns < 0 on error and errno / WSAGetLastError is set
  • recv() definitely returns = 0 when the other side closed the connection
  • recv() definitely returns > 0 when data was read

MSDN also says:

Using the closesocket or shutdown functions with SD_SEND or SD_BOTH results in a RELEASE signal being sent out on the control channel. Due to ATM's use of separate signal and data channels, it is possible that a RELEASE signal could reach the remote end before the last of the data reaches its destination, resulting in a loss of that data. One possible solutions is programming a sufficient delay between the last data sent and the closesocket or shutdown function calls for an ATM socket.

This is regarded in the example of recv() and send(): http://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspx

But still no success, I still get some interrupts in 10% of all connections after the 49 Byte is received, 90% of the connections succeed. Any ideas? Thx.

Abe answered 10/5, 2012 at 1:26 Comment(2)
I suspect you are making one of several classic socket programming mistakes. I have a few ideas, but I'd rather see your code first before writing something up.Alburga
SO_LINGER with a positive timeout in non-blocking mode doesn't make sense. It won't block or timeout.Gyrostatic
P
18

recv() returns 0 only when you request a 0-byte buffer or the other peer has gracefully disconnected. If you are not receiving all of the data you are expecting, then you are not reading the data correctly to begin with. Please update your question with your actual code.

Paralyse answered 10/5, 2012 at 1:42 Comment(2)
recv() returns 0 only when you request a 0-byte buffer or the other peer has gracefully disconnected. No matter it's non-blocking or blocking mode?Mylander
@Mylander that is correct. recv() returns either 1) < 0 on error (including (WSA)WOULDBLOCK, EAGAIN, etc in non-blocking mode), 2) 0 on graceful disconnect or 0-byte read, or 3) > 0 on a successful read of 1 or more bytes. Period.Paralyse
K
0

My guess is that you're not really sending all the data you think your are sending. Check out:

The Ultimate SO_LINGER page

Kuhns answered 20/6, 2013 at 13:40 Comment(2)
What does SO_LINGER have to do with not sending all the data you think you're sending?Gyrostatic
Because that is the whole SO_LINGER problem. You write all your data (you think) and close your socket. What you really did was put the data on the os's send buffer... and then closed the socket. The other side sees partial data and then a close.Kuhns
I
-1
  • recv() definitely returns = 0 when the other side closed the connection

This is not completely true, in the following code using non-blocking winsock2 tcp, when no data is available, select returns 1 and recv returns 0, as does WSAGetLastError().

fd_set test = {1, socket};
const timeval timeout = {0, 0};
if (!::select(0, &test, nullptr, nullptr, &timeout)) return 0;
int done = ::recv(socket, buffer, 1, 0);

This continues even after the other end has called:

::shutdown(socket, SD_BOTH);
::closesocket(socket);

and then ended. Communication works as expected, it is just ::recv that seems to be "broken".

Ingrowth answered 17/6, 2020 at 10:3 Comment(1)
If recv() returns zero the peer has closed the connection. Non-blocking mode has nothing to do with it.Gyrostatic

© 2022 - 2024 — McMap. All rights reserved.