2

in one of my projects I have implemented a small HTTP server to stream the video data of a connected webcam. For this task I'm utilizing the System.Net.Sockets.TcpListener from .NET Framework 4.5, which listens to a pre-configured endpoint and uses the AcceptSocketAsync() mtehod to wait for incomming requests. You can see the relevant code parts below:

this.server = new TcpListener(endpoint);
this.server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 0));
this.server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
this.server.Start();
...
this.listenTask = Task.Factory.StartNew(this.Listen);

...

private async void Listen()
{
    try
    {
        while (this.server.Server.IsBound)
        {
            Socket socket = await this.server.AcceptSocketAsync();
            if (socket == null)
            {
                break;
            }

            Task.Factory.StartNew(() => this.ClientThread(socket));
        }
    }
    catch (ObjectDisposedException)
    {
        Log.Debug("Media HttpServer closed.");
    }
}

This works fine, when I start the application and the HTTP server is started for the first time. However, when I stop the HTTP server (done via CheckBox in the settings of the application) the unverlying listening socket is sometimes not closed. When I check for the state of the sockets via console (netstat -ano) I can see that the socket is still in state LISTENING. The resulting problem is, when I restart the HTTP server again I get an System.Net.Sockets.SocketException with the message "Only one usage of each socket address is normally permitted", which is not surprising.

The relevant code part for stopping the HTTP server is as follows:

...
if (this.server != null)
{
    if (this.server.Server != null)
    {
        if (this.server.Server.Connected)
        {
            this.server.Server.Shutdown(SocketShutdown.Both);
            this.server.Server.Disconnect(true);
        }

        this.server.Server.Close();
    }

    this.server.Stop();
}
...

I also keep track of my open connections and close them after finishing the transmission of data and when stopping the server. None of the connection sockets stays opened, so I believe only the listening socket should be relevant for this problem.

I already tried various combinations/orders of the Shutdown(), Disconnect(), Close() and Stop() methods when stopping the server, as well as setting/unsetting several options when starting the server like Linger and ReuseAddress, which sometimes seemed to fix the problem at first, but then a few days later the problem occurred again.

I also tried to "force" the listening socket to close when stopping the server using GetTcpTable(...) and SetTcpEntry(...) from iphlpapi.dll, as described in this question: How to close a TCP connection by port? Unfortunately, this approach did not work for me (it change anything about the state of the listening socket at all).

As I'm a little bit clueless of what else I could do, I'm asking here if somebody has an idea of what might cause the discribed problem or how to solve it. Any help would be greatly appreciated.

Kind regards, Chris

Community
  • 1
  • 1
W64BugBear
  • 81
  • 1
  • 6
  • 1
    You have fallen victim to the superstitious dispose pattern. You dispose in lots of ways and check for all kinds of conditions. `server.Dispose();` would have been enough and would not have produced this problem. – usr Jul 02 '14 at 10:43

4 Answers4

2

You should almost always leave TcpListener.Server alone. It's there so you can set socket options on it, not use it for control purposes.

So your Listen should be:

private async void Listen()
{
    try
    {
        while (true)
        {
            Socket socket = await this.server.AcceptSocketAsync();
            if (socket == null)
            {
                break;
            }

            Task.Run(() => this.ClientThread(socket));
        }
    }
    catch (ObjectDisposedException)
    {
        Log.Debug("Media HttpServer closed.");
    }
}

(assuming you do actually want one thread per client, an architecture I do not recommend in general).

When you're ready to stop, just stop:

if (this.server != null)
{
    this.server.Stop();
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

If you do not have any special requirement, it is suggested to make use of TcpListener class and its methods only or if you have such requirement, do not use TcpListener and start with the Raw socket.

TcpListener class is self sufficient to provide method like

Start(), AcceptTcpClient() and Stop().

You can create a List<TcpClient> and loop through each client and call client.close() after calling Stop() on the TcpListener instance.

A very good example of client server communication is on MSDN: http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=vs.110).aspx

Regards

Kajal Sinha
  • 1,565
  • 11
  • 20
-1

On server socket, shutdown & disconnect is not needed for listening sockets. Those calls are needed only for connected sockets. Replace the socket stop with below code:

if (this.server != null)
{
    if (this.server.Server != null)
    {
        this.server.Server.Close();
        this.server.Server = NULL;
    }

}
dvasanth
  • 1,337
  • 1
  • 9
  • 10
-2

I would dispose of your socket connections once you have closed them. The documentation says they should be disposed after closed but personally I like to say when to dispose of anything that use the IDisposable interface.

albal
  • 237
  • 1
  • 3
  • 19