2015-04-25 55 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