Socket Problem: Exclusive Bind

Tech-Archive recommends: Fix windows errors by optimizing your registry



Hello all,

I'm developing a TCP/IP message based client and server. Now, with the
server I have a strange problem which I can't get rid of without using a
strange work-around.

The server is intended to exclusively bind to a given interface and port. No
other application (or the same application) is allowed to bind to that
interface when a server component is already listening on that port.

When I bind the listening socket for the firt time, this works fine. When I
then close the socket and clear its reference, I expect the socket to have
unbound, releasing the port. But, when I recreate a listening socket and
attempt to bind it, it now gives me an "Address in use" exception.
Eventhough I closed down the previous listening socket. It won't be until a
while before the 2nd bind becomes successful, unless I close and restart the
application.

So, I've been searching and testing around as to why this socket doesn't
really want to close for some period of time. Then, I decided to fiddle
around some with the garbage collector. And guess what? After actively
garbage collecting, I could then bind to the address without exceptions.
Here an example of the "faulty" code:

public void Open()
{
if (_listener != null) return;
_listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
_listener.ExclusiveAddressUse = true;
_listener.Bind(new IPEndPoint(string.IsNullOrEmpty(_interface) ?
IPAddress.Any : IPAddress.Parse(_interface), _port));
_listener.Listen(10);
for (int counter = 0; counter < 1; counter++)
_listener.BeginAccept(_acceptCallback, new
SocketState(_listener));
InternalStateChange(TcpipState.Listening);
}
public void Close(bool gracefully)
{
if (_listener == null) return;
_listener.Close();
_listener = null;

// Current active client connections are closed here.
}

Looking at this code, one would expect the server could be opened
immediately after close has been called without exceptions. But it won't. On
a 2nd Open() the "Address in use" exception is thrown on me unless I wait
for anywhere between 5 and 90 seconds.

Then, added this work-around which allows me to close and instantly open the
server again.

public void Open()
{
if (_listener != null) return;

#region Extremely dumb workaround using the garbage collector in
order to exclusively bind to an addres that's still occupied by a "closed"
socket.

for (int counter = 0; counter < 5; counter++)
{
_listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
_listener.ExclusiveAddressUse = true;
try
{
_listener.Bind(new
IPEndPoint(string.IsNullOrEmpty(_interface) ? IPAddress.Any :
IPAddress.Parse(_interface), _port));
break;
}
catch (SocketException)
{
_listener = null;
GC.Collect();
if (counter == 4) throw;
}
}

#endregion

_listener.Listen(10);
for (int counter = 0; counter < 1; counter++)
_listener.BeginAccept(_acceptCallback, new
SocketState(_listener));
InternalStateChange(TcpipState.Listening);
}

What this does, is to attempt to bind to the address 5 times. If an address
in use exception is thrown, the garbage collector is called each time. After
the 5th time of trying it gives up and rethrows the exception.

Attempting this 2 times is not enough, but attempting to bind 5 times in
this loop is enough to bind guaranteed.

This altogether means, that the garbage collector cleans up something of the
previously bound sockets which the socket's Close() method does not. What
gives? On Win32 I never had this problem. When I closed a socket there, I
could instantly rebind to it.

Point is.. I just want to be able to restart the server immediately after it
has shut down, and not wait for an undetermined amount of time. Calling the
GC to accomplish cleanup which apparently is needed doesn't seem a very
graceful way to get it to work :(

-Magic


.



Relevant Pages

  • RE: Problems with SO_REUSEADDR
    ... The SO_REUSEADDR socket option serves four different purposes: ... SO REUSEADDR allows a listening server to start and bind its well-known ... port even if previously established connections exist that use this port as ... A listening server is started. ...
    (microsoft.public.win32.programmer.networks)
  • Re: Windows "C" vs TCL sockets
    ... Still doesn't fix it. ... Sounds like your server isn't on an interface that's routable to the ... Did you bind() before connect? ... Given that Tcl's socket ...
    (comp.lang.tcl)
  • Re: InterNetwork communication
    ... >> to be able to send a command to the server and the server respond with an ... > The simple answer is not close the socket at either the client or server ... > Once you have the TcpClient object from the listener start a separate ... > close the TcpClient object when the listener receives a command like "quit". ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Java Socket Constructor
    ... bind() simply binds a socket to an interface/port locally for both client ... After that you can connectto a server. ...
    (comp.lang.java.programmer)
  • Re: max connections
    ... When you'll send data in such situation server which closed that socket on ... The time in between the last accept en close listener is ... server is now limited by 16 connections simultaneously. ...
    (microsoft.public.win32.programmer.networks)