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を呼び出すことによってスローされる可能性のあるSocketExceptionsをキャッチします。

于 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 に答える