The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

C# and Socket related question (requires some depth of TCP..)

I've run into a peculiar problem - it's possible I'm stupid and am missing something.

I have an application that's running as a socket server and listens of a specific port. I'm using the .NET (1.1) Socket implementation.

The peer (a client application) sometimes disconnects (which is OK) but I never realize it has, the Sock.Connected does not tell me so, the Sock.Poll(..) with SocketError flag does not tell me so.. etc. I then fired up ethereal to dig deeper, and this is what happens (at TCP level)

my server                      client
      <-----------FIN------------
      ---------ACK--------------->

      <.........nothing else.......>

My understanding of FIN is that the sender is saying "I don't have anything more for you" but it really isn't a disconnect. So the client side is essentially closed, however, the server (my app) does not know that. I don't see a OS level FIN going out (and it may not, because I think a FIN goes out if a Sock.Close is called. But then I don't know if I should close the socket!)

The only way out is for me to monitor some sort of timeout, and then do a Sock.Shutdown and Close which sends out a TCP RST, that resets the connection.

My question is, is there a way for me to figure out that there was a incoming FIN so I can go ahead and close too? Or is it that the client should be sending a RST..? Any flag/variable I can check to deal with this condition?

(adding to the misery, since I don't know the other half is 'FINito' :) I try sending data and it doesn't get anywhere.And the socket layer STILL won't throw an exception!

Any gurus to help?

thanks plenty
v
Tuesday, February 14, 2006
 
 
The recv (or recvfrom) method of your socket class should indicate that the connection has been closed by returning 0 as the number of bytes read from the stream.

Check if 0 bytes are returned; if that's the case call socket.close.
Curious
Tuesday, February 14, 2006
 
 
After a first FIN/ACK pair, the state FIN WAIT 2 is entered and another FIN/ACK pair is required for the connection to be closed. I suppose you could detect the first FIN/ACK and close the connection (that was your question, right?), but I don't think it will be easy unless you use raw sockets or do some driver hooks... Anyway, first I suggest you don't do this and let the TCP protocol do what it is supposed to do and second this wouldn't really help you. Because the client might loose the connection because of some external factor (like cable unplugged) and you won't even receive a FIN, i suppose.
A solution? Normally a TCP socket knows if a write fails but doesn't know if a read fails. You say you write and still don't get an exception? Try investigating this problem further. Besides that, the most reliable solution is to set KeepAlive to some reasonable value OR (because it can slow things down) implement your own keep-alive mechanism, which you can better tweak according to your needs. A very simple one would be something like: if there was no activity for n seconds send some magic packet and wait for a response.
smalltalk Send private email
Tuesday, February 14, 2006
 
 
Curious, the connection is not yet closed, so read will not fail. The aim is to close the connection.
smalltalk Send private email
Tuesday, February 14, 2006
 
 
Curious,

That won't help, as smalltalk mentioned - the recv will return 0 but that doesn't mean that the other half of the connection is actually closed.

Smalltalk, I prefer not to use low level socket options when I was using an abstract implementation like the .NET socket. I'm not using keep alive but I do have my own "alive time" after which I forcibly close down the socket. The problem is, in the scenario I'm functioning, the time delay between the last FIN and the time at which I actually close the socket poses some problems..

oh well, maybe it's time I talk to the guy on the other side (we have some control over both ends of the app.) and make sure he does a RST after the FIN...
v
Tuesday, February 14, 2006
 
 
One solution I have heard to deal with this problem is to run a low priority server thread that calls select() on the client sockets. If a socket is readable and writable, assume that the client is still connected.
MBJ Send private email
Tuesday, February 14, 2006
 
 
Maybe I didn't understand your question. What do you really want to do? You want to handle the case when the client explicitly closes the connection or the case when the connection is lost? What language is the other application written in? And why would you require it to send a RST?
smalltalk Send private email
Tuesday, February 14, 2006
 
 
> recv (or recvfrom) method ... indicate[s] that the
> connection has been closed by returning 0 ... bytes
> read from the stream.
> Check if 0 bytes are returned; if that's the case
> call socket.close.
>  -- Curious

Googling socket recv() provides many man pages that support Curious's statement :

> If no messages are available to be received and the
> peer has performed an orderly shutdown, recv() shall
> return 0.
>  -- http://www.opengroup.org/onlinepubs/009695399/functions/recv.html



But this method relies on the server performing socket recv()'s before each/any socket send()'s :


server                    client
  <-----------REQ------------
recv() > 0
send()
  -----------REPLY---------->


  <-----------REQ------------
recv() > 0
send()
  -----------REPLY---------->

  <-----------FIN------------
  ------------ACK----------->
recv() = 0
close()
  ------------FIN----------->
  <-----------ACK------------


Thus, if your server always performs socket recv()'s before any socket send()'s, then as soon as recv() returns 0, the server knows the other side closed the connection & the server can now continue to send() or close().


If your server NEVER recv()'s after some point but only performs send()'s, then it's a little harder to know exactly when the other side has closed the connection.



But search socket (UNIX, BSD, Windows, etc.) man pages for ideas & examples.
Ian Johns
Tuesday, February 14, 2006
 
 
smalltalk,

My server is in C#, the other one is in C but that doesn't matter. In this setup, the client routinely connects and then disconnects after a few seconds - think of something like a heartbeat.

The problem is, the client seems to be sending a FIN, but that's not sufficient for me to realize that the connection is no longer viable. And that in turn causes my keep-alive (my own implementation) to timeout after about 'X' seconds, and then I do a socket close.

We don't need that delay, and the socket should close right away - that's the problem. I think you did understand my question right :)

MBJ - .NET has a Socket.Poll(...) method (not socket select) which also has a case that looks at errors on the socket, but that never returns a failure. The case you mention is useful if I were to find out if the socket actually closed. But in my case, that's not happening - which is why all the drama :)
v
Tuesday, February 14, 2006
 
 
Ian,

At this point, I don't know how exactly the sock implementation on .NET behaves. But I take your point - let me investigate further and see if my Recv routines returning a 0 actually takes care of this situation.

If it does, my "thank you" to both you and Curious. I haven't  tried this scenario thought. ANd yes, I do have receives frequently and I can check if it does return a 0.
v
Tuesday, February 14, 2006
 
 
A suggestion from MSDN is to do a zero-byte Send (or BeginSend).  If it fails, you know the socket is closed.
example Send private email
Tuesday, February 14, 2006
 
 
example - I had already tried that before the post, I've noticed that a send with 'n' bytes tells me that 'n' bytes were sent :( (but those bytes can't even ben seen at ethereal which implies they actually weren't sent - but the routines don't give me an indication) so that did not help.

Tomorrow I'll be trying the case that Curious and Ian mentioned and I'll post my results.
v
Tuesday, February 14, 2006
 
 
You have to read to know the other side has closed. If you are writing check for return failure and something like an errno of EPIPE.
son of parnas
Tuesday, February 14, 2006
 
 
Thank you all for the responses. It's solved now - like how curious and Ian mentioned.

Just so someone else may find it helpful - pseudocode

if(Sock.Poll(...,SelectRead))
{

if((n = Sock.Receive(hdr, 0,len,SocketFlags.None)) <= 0 ) {
      ..do something..other side is indicating a close..               
  }
}

duh!

Thanks everyone.
v
Wednesday, February 15, 2006
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz