Gracefully disconnecting a TCP server

  • Thread starter Thread starter Andreas Håkansson
  • Start date Start date
A

Andreas Håkansson

Hello,

I'm building a small TCP based server which uses the Async commands. When
a new connection is made to the server, I store the new socket in a
hashtable,
using the client IP as the key.

Then I have a method in my server which is called Stop(). Now I would like
for
some advice on how to close down the server in a gracefull manner. I tried
the
following (Note: pesudo code not VB.NET ;)

ForEach ClientSocket In The HashTable
ClientSocket.Shutdown(SocketShutdown.Both)
ClientSocket.Close()
Remove the ClientSocket from the HashTable
End ForEach

Server.Shutdown(SocketShutdown.Both)
Server.Close()

However when I do this, the Server.Shutdown(SocketShutdown.Both) call throws
an exception telling me I tried to do something on a socket which is already
connected.

Suggestions, solutions etc for a gracefull shutdown schema is welcome =)

//Andreas
 
Andreas Håkansson said:
Hello,

I'm building a small TCP based server which uses the Async commands. When
a new connection is made to the server, I store the new socket in a
hashtable,
using the client IP as the key.

Then I have a method in my server which is called Stop(). Now I would like
for
some advice on how to close down the server in a gracefull manner. I tried
the
following (Note: pesudo code not VB.NET ;)

ForEach ClientSocket In The HashTable
ClientSocket.Shutdown(SocketShutdown.Both)
ClientSocket.Close()
Remove the ClientSocket from the HashTable
End ForEach

Server.Shutdown(SocketShutdown.Both)
Server.Close()

However when I do this, the Server.Shutdown(SocketShutdown.Both) call throws
an exception telling me I tried to do something on a socket which is already
connected.

Suggestions, solutions etc for a gracefull shutdown schema is welcome =)

//Andreas

I am having the same problem with my C++ TCP server. I get error
WSAENOTCONN (10057) when I call shutdown on my listener socket. I do not
get the error on other sockets though, only the listener socket. I am
interested in seeing any replies to this thread.

PS-
You should reconsider your shutdown technique above. The correct way to do
it is to shutdown the sends and then call recv on the socket until there is
no more data. Your technique has a potential to lose data.
 
Trevor said:
I am having the same problem with my C++ TCP server. I get error
WSAENOTCONN (10057) when I call shutdown on my listener socket. I do not
get the error on other sockets though, only the listener socket. I am
interested in seeing any replies to this thread.

PS-
You should reconsider your shutdown technique above. The correct way to do
it is to shutdown the sends and then call recv on the socket until there is
no more data. Your technique has a potential to lose data.

Should I do this for each "ClientSocket" in the HashTable or only on the
listener
socket and skip the entire "ForEach ClientSocket In The HashTable" section?

//Andreas
 
Andreas Håkansson said:
Should I do this for each "ClientSocket" in the HashTable or only on the
listener
socket and skip the entire "ForEach ClientSocket In The HashTable" section?

//Andreas

Andreas,

Yes, you should do this for each "ClientSocket" in the HashTable. The
listener socket should not have any data being sent or received on it so it
is not an issue on the listener socket. You just want to make sure that the
socket is empty (read & sends) before you forget about it completely or you
may lose data.
 
Trevor said:
Andreas,

Yes, you should do this for each "ClientSocket" in the HashTable. The
listener socket should not have any data being sent or received on it so it
is not an issue on the listener socket. You just want to make sure that the
socket is empty (read & sends) before you forget about it completely or you
may lose data.

Any suggestions on how to wait in a correct mannor? If the recieve is done
in
an async mannor then you can't be quite sure when data which has been
transmitted before the Shutdown.Send has been ordered will arrive. One of
the reasons for this has to be the ThreadPool which is used by the async
socket operations internally. Since the ThreadPool is per process, if the
process uses a lot of pooled threads then you won't know when there will
be a free threat to handle the pending recieve operation(s), especially if
the
system is under load and the ThreadPool is limiting the number of threads
in the pool to reduce the overhead when context switching ?

Have I totally missunderstood this? How the heck do I wait for an unknown
of queued async recives before closing the socket? Especially since my
Stop() method is called async? Do I need to include an async Stop() call
(BeginStop/EndStop) ?

//Andreas
 
Andreas Håkansson said:
Any suggestions on how to wait in a correct mannor? If the recieve is done
in
an async mannor then you can't be quite sure when data which has been
transmitted before the Shutdown.Send has been ordered will arrive. One of
the reasons for this has to be the ThreadPool which is used by the async
socket operations internally. Since the ThreadPool is per process, if the
process uses a lot of pooled threads then you won't know when there will
be a free threat to handle the pending recieve operation(s), especially if
the
system is under load and the ThreadPool is limiting the number of threads
in the pool to reduce the overhead when context switching ?

Have I totally missunderstood this? How the heck do I wait for an unknown
of queued async recives before closing the socket? Especially since my
Stop() method is called async? Do I need to include an async Stop() call
(BeginStop/EndStop) ?

//Andreas
Andreas,
I'm sorry I can't help you here. I have never programmed sockets with
..NET. However, I can tell you that there is a native function to check if a
socket has incoming / outgoing data queued up. If it helps, the native
function is called "select" and is a implementation of the BSD socket select
function. If you can't figure out a ".NET way" to do it then you can always
P/Invoke this function (as long as you have access to the SOCKET handle in
..NET).
 
Seems that the Socket.Available property will tell you if there is
any recieved data to read from a socket. However I have yet to
figure out how to check if there are any data waiting to be sent
from the server to the client before the socket is closed.

There is a static function called Socket.Select but I couldn't find
anything which would help. Another method was Socket.Poll
but it didn't either seem to help.


//Andreas
 
Andreas Håkansson said:
Seems that the Socket.Available property will tell you if there is
any recieved data to read from a socket. However I have yet to
figure out how to check if there are any data waiting to be sent
from the server to the client before the socket is closed.

There is a static function called Socket.Select but I couldn't find
anything which would help. Another method was Socket.Poll
but it didn't either seem to help.


//Andreas

Andreas,

I took a quick look at Socket.Select and it is indeed the .NET
implementation of select() that I was referring to in my previous post. If
I am reading this documentation correctly, you need to create two IList
objects, both of which contain the same socket (client socket who is
interested in disconnecting) and pass them to the checkRead & checkWrite
parameters of Socket.Select.

PSEUDO code:
--------------
IList read, write, err;
// Copy Socket handle to each IList
read = new IList(thesocket);
write = new IList(thesocket);
err = new IList(); // not interested in error, but the function requires
that you do not pass it NULL so give it an empty IList.
Socket.Select(read, write, err, 1000000); // block thread for 1 sec at the
most.
if (read.Count == 0)
{
// no more incoming RX data.
}
if (write.Count == 1)
{
// no more incoming TX data.
}

That should give you a rough idea of how it works. Keep in mind that I am
not a .NET programmer and this is pseudo code so don't expect it to work in
your compiler. You will need to loop until there is no more incoming RX
data and there is no more outgoing TX data.
 
Back
Top