2012-11-22 50 views
2

我試圖取消任務使用CancellationTokenSource網絡IO等待,但我要等到TcpClient的連接:如何取消正在等待的任務?

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

任何想法?

其次,在單獨的任務中啓動每個客戶端可以嗎?

+0

TCP類應該有接受某種形式的取消,或超時,這樣就可以的方法在循環中每次超時後檢查CancellationToken。 – Servy

+0

僅限AFAIK .net 4.5有此選項。 – user1748906

+1

相關:http://blogs.msdn.com/b/pfxteam/archive/2012/10/05/how-do-i-cancel-non-cancelable-async-operations.aspx – Servy

回答

0

我用的CancellationToken處理,而不是創建一個新的,它使代碼更簡單

var task = Listener.AcceptTcpClientAsync(); 
task.Wait(MainToken.Token); 
MainToken.Token.ThrowIfCancellationRequested(); 
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。