recv() returns 0 without connection being closed

I've written a program consisting of a server and a client that has been online for almost 20 years, of course including a few dozen updates over the years.
Both ends written in C++ using the win32api including wsock32.

For the first 15 years or so this has worked just fine, but then, not exactly sure when, a few years ago, the clients would lose connection once in a while, maybe 2 or 3 times a day.
No big deal, as a quick fix I've implemented a button to reconnect and that was it for the time being.
Now I have a bit more time and I've decided it's time to fix this for good.

I've stripped both ends of the program down to the bare connection, doing nothing but sending 6 bytes of data back and forth every 10 seconds to keep the connection alive and I've moved the server end to my own PC, meaning the 2 ends are now both running on my own PC (with win10pro on it), connect via "localhost" which will work even if my PC isn't connected to the web at all.
I've used Wireshark to monitor the packages exchanged between the two ends.

I do not have the slightest clue why, but a few times a day, sometimes 10 minutes, sometimes 10 hours or more after program start, the recv() function on the server end returns a 0 and closes the connection after which the client end loses connection, where WSAGetLastError() on the server end returns 0 and on the client end returns 10053 which stands for connection closed from the other end.

I really have no clue what this could be, the code is a simple connection procedure as one can find in beginners courses, plain and easy, with the recv() function in a thread and a timed send() function in another thread that does nothing but send the same 6 bytes every 10 seconds.
Especially after this code has worked for some 15 years and this particular part hasn't changed at all I'm really clueless why the connection terminates.
I mean a connection that remains stable for up to 10 hours and literally does nothing but send the same 6 bytes back and forth, why would it terminate once in a while?

Wireshark doesn't show anything unusual either, it shows the 6 bytes sent back and forth every 10 seconds plus an ACK package for confirmation up to the point where the server end closes the connection for no reason.
Last edited on
or the first 15 years or so this has worked just fine, but then, not exactly sure when, a few years ago, the clients would lose connection once in a while, maybe 2 or 3 times a day.
Have the OS versions changes? Does this change correspond to a move from Windows 7?
It seems to make no difference.
On the server where this normally runs on, there was Win2000 installed on start, later on updated to WinXP (long before these disconnects started) and that's still there today, even though obsolete, I simply do not need any server functions that would require a better OS.
On my own PC I'm running win10pro and aside of me stripping the program of all functions for testing purpose, the behavior of the server.exe is identical on XP as well as on Win10pro.
Last edited on
Is it possible that you might send/recv simultaneously on the server?
Yes, sure, send and recv are in separate threads, using the same socket, so it's very well possible that both have something to do at the same time.
At the very least, since recv is blocked waiting for something to come in, the send thread will still send its 6 bytes every 10 seconds.
Last edited on
Sockets don't like that. You have to syncronise your send/recv. On Windows, that's pretty easy as there are loads of sync objects.

You're probably seeing more of it because of faster networks, host or both. That's normal. Comms libraries often break when things speed up. It makes rare race conditions more likely.
Last edited on
Ackkkkkk, now that's bad news.
I mean ok, how to sync things I know in general, but then, how do you sync between a blocking recv and a timed send?
Don't tell me I cannot send anything while the recv is waiting?

Edit: Looked it up on the web, found this one (among many others) who clearly say, sockets are bidirectional and thread safe, there's no sync needed.
https://cboard.cprogramming.com/c-programming/150774-parallel-threads-socket-send-recv.html#post1123320
Last edited on
Before doing a blocking read, use select() to check if there's anything pending.

If you need help with that I can knock up something.
Over the last 20 years I've had quite a few different versions of the program running, including one with non blocking sockets, where send and recv were in the same thread.
I found that rather unpractical and the performance not as good as with blocking sockets.

Sure, if I find no other solution I will have to get back to non blocking sockets, but given how many tutorials there are on the web all advising for blocking sockets and separate threads for send and recv I find it hard to believe that sockets shouldn't be thread safe.
I'm not suggesting you change the architecture of your app, or resort to non-blocking sockets.

I'm suggesting the creating of a function like: isDataAvailable(SOCKET s) that you can use before calling recv(), pretty much guaranteeing recv() doen't block, with blocking sockets.

You implement such a function by setting up a read FD_SET, then calling select() with a zero timeout. Select returns 0 (timeout) or 1 (data available) or -1 (you've been bad).
For one, that's near identical to non blocking sockets, only that you use a blocking socket to read it only when data is available.
For two, I kept reading on the web and I can't find any information anywhere that sockets shall not be bidirectional and thread safe, you're the only one saying that while 100s of others including dozens of tutorials say the opposite.
If blocking sockets were a problem and one would have to work around the blocking, there would be 1000s of articles all over the web warning coders not to use them and/or explaining how to solve the problem.
Last edited on
that's near identical to non blocking sockets
No it isn't. You can do something like:
1
2
3
4
5
6
7
8
9
while true
    if data available on s {
        acquire your lock on s
        read s
        break
    }
    else {
        sleep
    }

And in the writer thread:
1
2
3
4
    {
        acquire your lock on s
        send s
    }

I think that's an easy amendment to make.

I kept reading on the web and I can't find any information anywhere that sockets shall not be bidirectional and thread safe, you're the only one saying that while 100s of others including dozens of tutorials say the opposite
Fine. I'm not saying that.

Sockets are bidirectional. In fact, they replace a protocol that wasn't, that's why the FTP protocol (which predates sockets) is bonkers.

I am saying that you cannot read and write on a socket at the same time from different threads. That is a race condition that breaks the socket.
Last edited on
Topic archived. No new replies allowed.