Im new to winsock and am trying to make a simple server and client (blocking sockets). However, I am slightly confused.
My client sends some data to a server, and then the client invokes recv ready to get a response
--> the connection *seems* to have not been closed, although all data is sent
--> the server does not move on from recv
--> the server does not send its response.
If I close the client socket after send, signifying that the client has sent its data and that the connection is closed, and then re-open a socket everything is fine. This seems very inefficient, what am I doing wrong?
Hope that makes sense!
Posted on 2004-04-01 14:25:09 by adamjjackson
Hi adamjjackson,

I've done something similar over the past days (client, server, both with blocking sockets) and ran into the same problem. Apparently, if both sides of the connection use blocking sockets, the client must actively indicate when it is done with sending.

It is not necessary to actually close the socket after sending. Instead, it is sufficient if the client disables further sending by calling "invoke shutdown, , 1". Thereby the (blocking) server gets the information that no more data will come in, and will switch to sending the response.

After receiving the response, the client should in fact close the socket because it cannot be re-used for further sending (according to my helpfile).

I hope that made sense.

Posted on 2004-04-01 17:17:49 by Frank
Okay, that makes sense - thank you. So what is the best option then? To make the server with non-blocking sockets (haven't used them yet!), or the client, or both?! I was using non-blocking sockets and in a worker thread for simplicity. I assume that re-creating the socket each time is not the best approach...
Posted on 2004-04-02 03:19:06 by adamjjackson
Hm, it sounds a bit weird to me that your messages are never received - both closing the socket and calling shutdown() to make sure the data goes through are major hacks.

Be aware that TCP/IP uses various network optimizations - one of them is to combine several small sends into one large. I believe this is called the Nagle algorithm, and it can be turned off (though you generally shouldn't do this). This can introduce some buffering delays.

Perhaps if you posted the source, somebody could pinpoint possible errors.

Btw, if you switch to non-blocking sockets, think twice before using the message-passing variant (WSAAsyncSelect), it doesn't offer particularly high performance. It's ok if you only have a few connections and a low data rate, though.

Also, be sure to check out Thomas' stuff at www.madwizard.org and the Winsock Programmer's FAQ at http://www.tangentsoft.net/wskfaq .
Posted on 2004-04-02 06:42:17 by f0dder
Okay maybe I should have been a bit clearer. The data sent from the client to the server is recieved, in full. However, if the client calls recv immediately after it has finished sending the data the connection is not closed. And so the basic recv loop on the server:

invoke recv,esi,ADDR tempBuffer1,TEMP_BUFFER_SIZE,0
test eax,eax
mov ecx,OFFSET g_errRead
jz _connClosed ; Return value 0 means connection closed.
je _error
jmp _readData

will not exit - it has recieved all the data but the connection has not been closed, so recv remains blocked and therefor the server cannot send a response. So there is no way round this with blocking sockets...? So would I be right in thinking that a non-blocking version would require all the recieved data to be parsed, or some kind of header to be sent so that I can determine when that piece of data is recieved in full?

I've read a few posts of yours about WSAAsyncSelect and WSAWaitForMultipleEvents. The first appears to be the simplest to begin with, and I don't require scalability/lots of connections, i'm just fiddling/learning at the min. I've also read Thomas' tut's, cheers for the links 'n' stuff!
Posted on 2004-04-02 11:36:04 by adamjjackson
WSAEventSelect+WSAWaitForMultipleEvents is not too bad, and it works pretty well, but you may want to start with WSAAsyncSelect + windows messages. It's a good idea to get experience with a bunch of different programming methods, anyway :)

However, your problem doesn't require async sockets, and while async sockets can be a bit nicer than blocking sockets under many circumstances, I think you should stick to blocking sockets, and fix the logic of your server app :)

Yes, you should do some sort of processing in the server app, to figure out when the client has logically stopped sending data. This could mean parsing the received data, or it could mean the client would start sending a "I'm gonna send this many bytes" message and the server waiting until it either recived this amount, or times out. This will depend very much on your protocol, and perhaps your protocol will have to be changed, too.
Posted on 2004-04-02 17:54:14 by f0dder
It will require both, I will need to parse to get the "I'm gonna send this many bytes"...
Thanks :)
Posted on 2004-04-03 04:32:52 by adamjjackson

both closing the socket and calling shutdown() to make sure the data goes through are major hacks.

Your own source sees that a bit differently:

2.10 - What's the proper way to close a TCP socket?

The proper sequence for closing a TCP connection is:

1. Finish sending data.
2. Call shutdown() with the how parameter set to 1.
3. Loop on recv() until it returns 0.
4. Call closesocket().

Also the helpfiles are full of words to the effect of "a return value of 0 indicates that the connection has been shut down gracefully". How would one shut down the connection gracefully, if not by using shutdown() ?


Posted on 2004-04-03 09:15:48 by Frank
There's no contradiction - the above snippet describes a clean socket shutdown. I was referring to the process of shuttding down + reopening a socket to make sure data has gone through.

Of course if sending the data is the clients final action and there's no further communication between the client and the server, the socket should be shut down (and cleanly).
Posted on 2004-04-03 10:08:38 by f0dder

There's no contradiction

Yes, you are right. I had managed to confuse myself, sorry.

Thank you

Posted on 2004-04-05 08:23:39 by Frank
No problem - I probably wasn't as clear as I could have been, so there was plenty of room for misinterpretation :)
Posted on 2004-04-05 09:19:22 by f0dder