2

我正在尝试使用 CancellationTokenSource 取消等待网络 IO 的任务,但我必须等到 TcpClient 连接:

try
{
    while (true)
    {
        token.Token.ThrowIfCancellationRequested();
        Thread.Sleep(int.MaxValue); //simulating a TcpListener waiting for request
    }
}

有任何想法吗?

其次,是否可以在单独的任务中启动每个客户端?

4

2 回答 2

3

当您启动任务时,您可以使用StartNew的重载来传递取消令牌,您的任务将检查取消。

或者,您可以只使用AcceptAsync并继续做其他工作。AcceptAsync 将调用通过您定义的 SocketAsyncEventArgs 参数附加的 OnCompleted 方法。

internal class Program
{
    private static EventWaitHandle _signalFromClient;
    private static readonly string NameThatClientKnows = Guid.NewGuid().ToString();
    private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();

    private const int PingSendTimeout = 30000;
    private static Socket _connectedClientSocket;
    private static Socket _tcpServer;

    private static void Main(string[] args)
    {
        _signalFromClient = new EventWaitHandle(false, EventResetMode.AutoReset, NameThatClientKnows);

        _tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _tcpServer.Bind(new IPEndPoint(IPAddress.Loopback, 0));
        _tcpServer.Listen(1);

        var asyncOpInfo = new SocketAsyncEventArgs();
        asyncOpInfo.Completed += CompletedConnectRequest;
        _tcpServer.AcceptAsync(asyncOpInfo);

        Console.WriteLine("Console stays open, connecting client will say something.");
        Console.ReadLine();
    }

    private static void CompletedConnectRequest(object sender, SocketAsyncEventArgs e)
    {
        Console.WriteLine("Client connected");

        _connectedClientSocket = e.AcceptSocket;

        Task.Factory.StartNew(SendSimpleMessage, CancellationTokenSource.Token);
    }

    private static void SendSimpleMessage()
    {
        while (!CancellationTokenSource.Token.IsCancellationRequested && _connectedClientSocket.Connected)
        {
            try
            {
                _connectedClientSocket.Send(Encoding.UTF8.GetBytes("PING"));
                _signalFromClient.WaitOne(PingSendTimeout);
            }
            catch (SocketException) { Dispose(); }
        }
    }

    private static void Dispose()
    {
        CancellationTokenSource.Cancel();

        _connectedClientSocket.Close();
        _tcpServer.Close();
    }
}

当然,使用缓冲区和其他必要的项目/行为设置 SocketAsyncEventArgs。在 Dispose() 中,我取消任务并捕获可能通过在客户端和服务器 ø_Ø 上调用 Socket.Close 引发的任何 SocketException。

于 2012-11-22T22:24:45.113 回答
0

我使用了 CancellationToken 句柄而不是创建一个新句柄,它使代码更简单

var task = Listener.AcceptTcpClientAsync();
task.Wait(MainToken.Token);
MainToken.Token.ThrowIfCancellationRequested();
于 2012-11-25T02:30:30.057 回答