【问题标题】:C# Asynchronous TCP Listener doesn't cancel loopC# 异步 TCP 侦听器不取消循环
【发布时间】:2018-06-09 21:56:52
【问题描述】:

我正在使用 TCPListener 类异步在 C# 中编写服务器。我目前有以下代码作为我的网络侦听器类:

public class NetworkListener
{
    private readonly SessionController _sessions;
    private readonly TcpListener _server;

    public NetworkListener(KernelConfiguration configuration, SessionController sessions)
    {
        _server = new TcpListener(new IPEndPoint(IPAddress.Any, configuration.Network.port));
        _server.Start();

        _sessions = sessions;
    }

    public async Task StartAccepting(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            var client = await _server.AcceptTcpClientAsync();
            Console.WriteLine($"New connection from {client.Client.RemoteEndPoint}.");
            _sessions.AddSession(client, Guid.NewGuid(), out var session);
            await session.StartReceiving();
        }

        Console.WriteLine("stop");
    }

    public void Dispose()
    {
        _server.Stop();
    }
}

作为我的 program.cs 我有:

internal class Program
{
    private static NetworkListener _networkListener;
    private static CancellationTokenSource _cancellationTokenSource;

    private static async Task Main(string[] args)
    {
        _networkListener = new NetworkListener(new KernelConfiguration(), new SessionController());
        _cancellationTokenSource = new CancellationTokenSource();

        var thread = new Thread(ProgressConsoleCommands);
        thread.Start();

        try
        {
            await _networkListener.StartAccepting(_cancellationTokenSource.Token);
        }
        finally
        {
            _networkListener.Dispose();
        }
    }

    private static void ProgressConsoleCommands()
    {
        while (true)
        {
            var command = Console.ReadLine();
            Console.WriteLine(command);

            switch (command)
            {
                case "close":
                    Console.WriteLine("called");
                    _cancellationTokenSource.Cancel();
                    break;
            }
        }
    }
}

目前发生的情况:

我启动我的程序。它启动 TcpListener。我可以连接到 TcpListener 正在监听的端口。当我输入“close”(当然没有引号)时,它会写“called”。但是,“停止”不会写入控制台,并且 TcpListener 仍在接受新问题。

所需状态:

每当我输入“关闭”时,它应该停止接受新连接,写入“停止”并退出循环。然后它应该调用我的 NetworkListener 类的 Dispose 函数来完全停止 TcpListener 并释放它。

【问题讨论】:

  • 您的解释出了什么问题有点令人困惑(至少对我而言)您能否尝试通过编辑您的帖子/改写/添加更多解释来澄清这一点?您还可以查看how to create a minimal, complete, verifiable examplehow to ask 您可以尝试通过在currentState 下声明您的CurrentState 和在wanted state 下的WantedState 来解决您的问题。我想这可以帮助我理解你的问题 :) 欢迎来到 StackOverflow!
  • 不完全确定,但您可能需要将CancellationToken 传递给AcceptTcpClientAsync
  • @CamiloTerevinto - 不幸的是,没有过载可以接受。但你说得对,这就是症结所在。一种(丑陋的)解决方案是在取消后打开一个环回连接,以便我们知道Accept 任务将完成。
  • @CamiloTerevinto 不,据我所知,它不接受任何参数。
  • 不幸的是,库中许多类的异步实现缺乏关键功能。只需关闭侦听器即可中止挂起的异步任务。

标签: c# asynchronous tcplistener


【解决方案1】:

在调用 AcceptTcpClientAsync() 之前,您可以先尝试在 while 循环中检查 TcpListener.Pending(),这样只有在实际有新连接需要处理时,循环才会阻塞。

https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.pending(v=vs.110).aspx

EDIT(0):如果这样做,您可能希望在 while 循环中添加 Thread.Sleep,以最大程度地减少 CPU 负载

EDIT(1):所以我的目标是这样的:

while (!token.IsCancellationRequested) {
    if (_server.Pending()) {
        var client = await _server.AcceptTcpClientAsync();
        // insert code for handling new connection
    }
    Thread.Sleep(500);
}

正如您所描述的,问题似乎是“await AcceptTcpClientAsync()”无限期地阻塞了while循环,直到一个新的客户端尝试连接到服务器。

正如@Damien_The_Unbeliever 在他的评论中指出的那样,您可以通过简单地为 TcpListener 提供一个新的客户端连接来解除阻塞(以一种肮脏的方式)。

然而,上面的例子应该 - 实际上 - 一旦 Thread.Sleep 过期就执行取消

【讨论】:

  • 但这仍然不能让我得到我想要的。
  • 见上文 EDIT(1)
  • @MichaelJagroep 不推荐使用Sleep 线程和socket,因为它会阻塞socket 的I/O Channel,或者任何I/O 流,从而影响程序的性能。跨度>
猜你喜欢
  • 2021-12-16
  • 2012-05-29
  • 1970-01-01
  • 2019-04-26
  • 2020-07-30
  • 2020-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多