问题描述
我创建了一个新的.NET Core工作者服务项目。此服务还应充当TCP套接字服务器,并侦听传入的消息。因此,基于the code sample from the docs,这基本上就是我要做的事情
public class Worker : BackgroundService
{
public override async Task StartAsync(CancellationToken cancellationToken)
{
TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"),1234);
tcpListener.Start();
try
{
while (true)
{
TcpClient tcpClient = await tcpListener.AcceptTcpClientAsync();
NetworkStream tcpClientStream = tcpClient.GetStream();
using StreamReader streamReader = new StreamReader(tcpClientStream);
string messageText = await streamReader.ReadToEndAsync();
// ... do things with messageText ...
}
}
catch (Exception exception)
{
// ... error handling ...
}
await base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(1000,stoppingToken);
}
}
}
将不再调用ExecuteAsync
方法,因为代码被卡在while
方法的StartAsync
循环中。当我注释掉整个重写的StartAsync
方法时,一切正常,ExecuteAsync
方法被调用。
是否有可能摆脱while循环的阻塞并利用事件处理程序或类似的东西?
解决方法
一个BackgroundService
的典型模式是它简单地覆盖ExecuteAsync
并等待stoppingToken
发出信号然后立即退出。
看看BackgroundService的源代码。
如果要使用“开始/停止”模式,请实施IHostedService
。
如果要使用BackgroundService
,则应这样布置:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"),1234);
tcpListener.Start();
try
{
while (!stoppingToken.IsCancellationRequested)
{
TcpClient tcpClient = await tcpListener.AcceptTcpClientAsync(); // READ BELOW ABOUT THIS
NetworkStream tcpClientStream = tcpClient.GetStream();
using StreamReader streamReader = new StreamReader(tcpClientStream);
string messageText = await streamReader.ReadToEndAsync();
// ... do things with messageText ...
}
}
catch (Exception exception)
{
// ... error handling ...
}
}
现在,这里最大的问题是AccpetTcpClientAsync
没有取消功能。因此,您可能必须实现something like this。
所以您可以这样做:
var tcpClient = await tcpListener.AcceptTcpClientAsync().WithCancellation(stoppingToken);
然后吞下在这种情况下将抛出的OperationCancelledExeption
。
编辑后添加
另一个选择是您可以一起跳过异步/等待版本,并使用Begin../End...
(在这种情况下为BeginAcceptTcpClient()
)。我倾向于沿着这条路走很多路。连接某些东西时触发事件触发是非常方便的。请记住,此时您的TcpListener
必须在类范围内,以免被丢弃。