如何异步等待连接?

How to wait for a connection asynchronously?

我设计了一个 class,它包装了一个 Socket 并允许发送和接收 through/from。由于接受、发送和接收是通过 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. 是的,因为你在阻止。你需要把它扔掉。
  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 线程。