【问题标题】:Do I need to call TcpListener.Stop()?我需要调用 TcpListener.Stop() 吗?
【发布时间】:2011-11-20 12:42:11
【问题描述】:

我将这段代码放在一个单独的线程(任务)中,该线程在应用程序启动时首先运行,并且在应用程序关闭之前不应结束:

TcpListener tcpListener = new TcpListener(IPAddress.Any, port);

tcpListener.Start();

while (true)
{
    TcpClient client = tcpListener.AcceptTcpClient();

    Task.Factory.StartNew(HandleClientCommunication, client);
}

在这种情况下需要调用tcpListener.Stop()吗?该线程在应用程序的整个持续时间内运行,如果我确实需要调用它,我会在哪里调用?侦听器是该线程的本地。我将有一个while (appRunning) 循环而不是while (true) 循环并在FormClosing 事件中将appRunning 设置为false?然后在while循环之后我可以调用tcpListener.Stop()

但是,是否有必要调用TcpListener.Stop(),因为此时应用程序已经关闭,并且由于我正在使用任务,所以进程也结束了?

【问题讨论】:

  • 开发人员发现有必要在 .NET 应用程序关闭时显式停止线程有几个原因 - 当他们看到其他开发人员这样做时,因为感觉“干净”或因为他们的工作线程读取/当表单关闭时,直接写入表单/组件/在应用程序丢失期间释放的任何数据(因此生成 AV/segfault 等)。您的侦听器线程本身似乎不需要显式停止任何操作,因此请让操作系统在主线程关闭并调用 ExitProcess() 时执行此操作。
  • @Jim:如果您想提供一些示例代码,说明如何在这种情况下实现取消令牌以解决此问题,我很乐意接受它作为答案 :)
  • @Jim Mischel - 如果 OP 大幅更改它,那么,是的,也许它可能需要在其他一些应用程序中停止。也许另一个应用程序需要在应用程序关闭之前停止它,但那是另一个应用程序。另外,也许我误解了取消机制——当请求取消时,阻塞的 AcceptTcpClient() 调用内部会发生什么?立即返回错误或异常?我想我应该查一下或尝试一下。
  • 好的,我能看到使用取消机制显式停止该线程的唯一方法是注册一个取消回调,通过在“localhost”上打开客户端连接来解除对 AcceptTcpClient() 调用的阻塞,(假设127.0.0.1 在绑定集中),因此导致 AcceptTcpClient() 返回实际连接。然后侦听器可以检查 token.IsCancellationRequested 并因此意识到它必须终止。这比让操作系统清理要混乱得多,除非绝对必要,否则我不会靠近它。操作系统非常非常擅长停止线程:)

标签: c# multithreading


【解决方案1】:

试试这样的:

public class Listener
{
    private readonly TcpListener m_Listener = new TcpListener(IPAddress.Any, IPEndPoint.MinPort);
    private CancellationTokenSource m_Cts;
    private Thread m_Thread;
    private readonly object m_SyncObject = new object();

    public void Start()
    {
        lock (m_SyncObject){
            if (m_Thread == null || !m_Thread.IsAlive){
                m_Cts = new CancellationTokenSource();
                m_Thread = new Thread(() => Listen(m_Cts.Token))
                    {
                        IsBackground = true
                    };
                m_Thread.Start();
            }
        }
    }

    public void Stop()
    {
        lock (m_SyncObject){
            m_Cts.Cancel();
            m_Listener.Stop();
        }
    }

    private void Listen(CancellationToken token)
    {
        m_Listener.Start();
        while (!token.IsCancellationRequested)
        {
            try{
                var socket = m_Listener.AcceptSocket();
                //do something with socket
            }
            catch (SocketException){                    
            }
        }
    }
}

使用TcpListener.Pending() 的方法不太好,因为您必须使用Thread.Sleep(miliseconds) 或类似的东西 - 客户端接受之间会有一些延迟(睡眠中的毫秒数),这很糟糕。

【讨论】:

  • 感谢您制作的精彩课程。这对我正在进行的项目非常有用。
  • 这个方案的问题是AcceptSocket方法被阻塞了。因此,在等待传入连接时,您无法优雅地停止侦听线程。
猜你喜欢
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-31
  • 2012-09-12
相关资源
最近更新 更多