拥有以下Async TCP服务器的参考代码,我想将CancellationToken传递给OnDataReceived
:
public sealed class TcpServer : IDisposable
{
private readonly TcpListener _listener;
private CancellationTokenSource _tokenSource;
private CancellationToken _token;
private bool _listening;
public event EventHandler<ConnectedEventArgs> OnDataReceived;
public TcpServer(IPAddress address, int port)
{
_listener = new TcpListener(address, port);
}
public async Task StartAsync(CancellationToken? token = null)
{
_tokenSource = CancellationTokenSource.CreateLinkedTokenSource(token ?? new CancellationToken());
_token = _tokenSource.Token;
_listener.Start();
_listening = true;
try
{
while (!_token.IsCancellationRequested)
{
await Task.Run(async () =>
{
var tcpClientTask = _listener.AcceptTcpClientAsync();
var tcpClient = await tcpClientTask;
OnDataReceived?.Invoke(tcpClient, new ConnectedEventArgs(tcpClient.GetStream()));
}, _token);
}
}
finally
{
_listener.Stop();
_listening = false;
}
}
public void Stop()
{
_tokenSource?.Cancel();
}
public void Dispose()
{
Stop();
}
}
public class ConnectedEventArgs : EventArgs
{
public NetworkStream Stream { get; private set; }
public ConnectedEventArgs(NetworkStream stream)
{
Stream = stream;
}
}
以下代码显示了我正在使用上述代码的方式,目前位于ReadStreamBytesAsync
我正在传递new CancellationToken()
,而我想从token
传递MainAsync
参数:
class Program
{
static void Main(string[] args)
{
InitAsyncWork();
Console.WriteLine("ended.");
Console.ReadKey();
}
static void InitAsyncWork()
{
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(cts.Token).GetAwaiter().GetResult();
}
static async Task MainAsync(CancellationToken token)
{
using (var server = new TcpServer(IPAddress.Any, 54001))
{
server.OnDataReceived += TcpClientOnlyReceive;
await server.StartAsync(token);
}
}
private static async void TcpClientOnlyReceive(object sender, ConnectedEventArgs e)
{
try
{
using (TcpClient client = (TcpClient)sender)
using (NetworkStream stream = e.Stream)
{
while (Utilities.IsTcpClientConnected(client))
{
if (client.Available == 0)
{
await Task.Delay(50);
continue;
}
byte[] rawX = await ReadStreamBytesAsync(stream, client.ReceiveBufferSize, new CancellationToken());
}//while(client.Connected)
}//using(client)using(stream)
}
catch (Exception ex)
{
Utilities.logger.Error("TcpClientOnlyReceive():Exception!!\r\nMsg: {1}\r\nStack: {2}", ex.Message, ex.StackTrace);
}
}
private static async Task<byte[]> ReadStreamBytesAsync(NetworkStream stream, int maxBytesToRead, CancellationToken token)
{
var bytesRead = 0;
var totalBytesRead = 0;
var clientMsg = new byte[maxBytesToRead];
byte[] contentBytes;
using (MemoryStream ms = new MemoryStream())
{
do
{
bytesRead = await stream.ReadAsync(clientMsg, totalBytesRead, clientMsg.Length - totalBytesRead, token);
await ms.WriteAsync(clientMsg, totalBytesRead, bytesRead, token);
totalBytesRead += bytesRead;
}
while (bytesRead > 0 && stream.DataAvailable);
contentBytes = ms.ToArray();
}
return contentBytes;
}
}
我应该将cts
定义为全局变量吗?或者修改ConnectedEventArgs
类,使其接受CancellationToken作为属性?
澄清: 根据收到的意见和1票投票结束这个问题!
ctrl+c
后关闭该应用程序,目前该应用程序阻止接受新连接,但它不会取消已建立的连接。