Proper way to stop TcpListener

2019-01-12 17:51发布

I am currently using TcpListener to address incoming connections, each of which are given a thread for handling the communication and then shutdown that single connection. Code looks as follows:

TcpListener listener = new TcpListener(IPAddress.Any, Port);
System.Console.WriteLine("Server Initialized, listening for incoming connections");
listener.Start();
while (listen)
{
     // Step 0: Client connection
     TcpClient client = listener.AcceptTcpClient();
     Thread clientThread = new Thread(new ParameterizedThreadStart(HandleConnection));
     clientThread.Start(client.GetStream());
     client.Close();
}

The listen variable is a boolean that is a field on the class. Now, when the program shuts down I want it to stop listening for clients. Setting listen to false will prevent it from taking on more connections, but since AcceptTcpClient is a blocking call, it will at minimum take the next client and THEN exit. Is there any way to force it to simply break out and stop, right then and there? What effect does calling listener.Stop() have while the other blocking call is running?

9条回答
老娘就宠你
2楼-- · 2019-01-12 18:06

Sockets provide powerful asynchronous capabilities. Take a look at Using an Asynchronous Server Socket

Here are couple of notes on the code.

Using manually created threads in this case may be an overhead.

The code below is subject to race conditions - TcpClient.Close() closes network stream you get through TcpClient.GetStream(). Consider closing client where you can definitely say that it is no longer needed.

 clientThread.Start(client.GetStream());
 client.Close();

TcpClient.Stop() closes underlying socket. TcpCliet.AcceptTcpClient() uses Socket.Accept() method on underlying socket which will throw SocketException once it is closed. You can call it from a different thread.

Anyway I recommend asynchronous sockets.

查看更多
看我几分像从前
3楼-- · 2019-01-12 18:13

listener.Server.Close() from another thread breaks the blocking call.

A blocking operation was interrupted by a call to WSACancelBlockingCall
查看更多
在下西门庆
4楼-- · 2019-01-12 18:13

See my answer here https://stackoverflow.com/a/17816763/2548170 TcpListener.Pending() is not good solution

查看更多
爷的心禁止访问
5楼-- · 2019-01-12 18:14

Some changes to make the Peter Oehlert anwer perfect. Because before 500 miliseconds the listener bloking again. To correct this:

    while (listen)     
    {
       // Step 0: Client connection     
       if (!listener.Pending())     
       {
           Thread.Sleep(500); // choose a number (in milliseconds) that makes sense
           continue; // skip to next iteration of loop
       }
       else // Enter here only if have pending clients
       {
          TcpClient client = listener.AcceptTcpClient();
          Thread clientThread = new Thread(new ParameterizedThreadStart(HandleConnection));
          clientThread.Start(client.GetStream());
          client.Close();
       }
   }
查看更多
等我变得足够好
6楼-- · 2019-01-12 18:15

Already mentioned above, use BeginAcceptTcpClient instead, it's much easier to manage asynchronously.

Here is some sample code :

        ServerSocket = new TcpListener(endpoint);
        try
        {
            ServerSocket.Start();
            ServerSocket.BeginAcceptTcpClient(OnClientConnect, null);
            ServerStarted = true;

            Console.WriteLine("Server has successfully started.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Server was unable to start : {ex.Message}");
            return false;
        }
查看更多
够拽才男人
7楼-- · 2019-01-12 18:19

Just to add even more reason to use the asynchronous approach, I'm pretty sure Thread.Abort won't work because the call is blocked in the OS level TCP stack.

Also... if you are calling BeginAcceptTCPClient in the callback to listen for every connection but the first, be careful to make sure that the thread that executed the initial BeginAccept doesn't terminate or else the listener will automatically get disposed by the framework. I suppose that's a feature, but in practice it's very annoying. In desktop apps it's not usually a problem, but on the web you might want to use the thread pool since those threads don't ever really terminate.

查看更多
登录 后发表回答