2015-04-25 91 views
1

我設計了一個包裝Socket的類,允許通過它發送和接收。由於接受,發送和接收都是通過UI完成的,我不希望它們阻止它,因此我使用了它們的異步版本。如何異步等待連接?

下面是相關代碼:

public void Accept() 
{ 
    // ... 
    // where resultAccept is a IAsyncResult 
    resultAccept = listener.BeginAccept(new AsyncCallback(AcceptCallback), null); 
} 

private void AcceptCallback(IAsyncResult ar) 
{ 
    connectedSocket = listener.EndAccept(ar); 
} 

public string Receive() 
{ 
    char[] data = new char[128]; 

    if (!resultAccept.IsCompleted) // (1) 
     resultAccept.AsyncWaitHandle.WaitOne(); 

    connectedSocket.BeginReceive(Encoding.UTF8.GetBytes(data), 0, data.Length, SocketFlags.None, 
           new AsyncCallback(RecvCallback), null); 

    // ... 
} 

當我開始接受,因爲沒有連線,它必須等待一(1)和蓋帽的UI(再次,我不想)。
另外,當連接被接受時,我得到一個NullReferenceException,因爲當BeginReceive開始時,AcceptCallback是,被觸發,但還沒有完成,所以connectedSocket仍然需要初始化。

  1. 爲什麼我的方法錯了?
  2. 是否有可能實現我想要的異步套接字?
  3. 如何防止UI在等待連接時被阻塞並確保對象的有效性?

回答

1
  1. 是的,因爲你是封鎖。你需要把它扔掉。
  2. 是的,在Web上有Socket擴展方法可以將過時的APM模式適配到TAP模式,以便您可以使用await。這個練習變得微不足道了。

您的代碼應該是這樣的:

async Task RunServer() { 
Socket serverSocket = ...; 

while (true) { 
    RunConnection(await serverSocket.AcceptAsync()); 
} 
} 

,然後提供Task RunConnectionAsync(Socket s)功能是異步爲好。一旦離開過時的APM模式就很簡單了。

或者,只使用線程和同步IO。這樣做沒有錯。儘管如此,await稍微好一些,因爲它會自動回傳給UI線程。

+0

但是,如果線程+同步IO可以工作,那麼異步套接字有什麼問題? – edmz

+0

你的意思是爲什麼有人會使用它們?異步保存線程並使其更容易使用UI線程。除此之外,幾乎沒有理由去異步,但有理由不這樣做。異步現在是一種時尚。另外大多數套接字教程都是令人尷尬的錯誤。 – usr

+0

啊,所以我現在使用的甚至已經過時了。無論如何,你說「只使用線程和同步IO」,所以我想知道爲什麼不能異步套接字能夠完成,如果一個線程+同步套接字可以,這是一個異步套接字做的。希望你能明白我的意思。 – edmz