C# 异步 TCP 侦听器不取消循环
Posted
技术标签:
【中文标题】C# 异步 TCP 侦听器不取消循环【英文标题】:C# Asynchronous TCP Listener doesn't cancel loop 【发布时间】: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 example 和how to ask 您可以尝试通过在currentState 下声明您的CurrentState 和在wanted state 下的WantedState 来解决您的问题。我想这可以帮助我理解你的问题 :) 欢迎来到 ***! 不完全确定,但您可能需要将CancellationToken
传递给AcceptTcpClientAsync
@CamiloTerevinto - 不幸的是,没有过载可以接受。但你说得对,这就是症结所在。一种(丑陋的)解决方案是在取消后打开一个环回连接,以便我们知道Accept
任务将完成。
@CamiloTerevinto 不,据我所知,它不接受任何参数。
不幸的是,库中许多类的异步实现缺乏关键功能。只需关闭侦听器即可中止挂起的异步任务。
【参考方案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 流,从而影响程序的性能。跨度>
以上是关于C# 异步 TCP 侦听器不取消循环的主要内容,如果未能解决你的问题,请参考以下文章
哪种 SSL 证书可以确保 Amazon Lightsail 实例上的 C# 侦听器与 iOS 应用程序之间的安全 TCP 连接?