[更新2014]:自本回答发布以来,示例已被修改,如此主题所述。现在的MSDN示例可以正确地处理多个传入连接。无论如何,这里描述的一般方法是正确的,或许可以提供额外的澄清。
进行套接字通信时,您基本上拥有一个用于所有传入连接的监听器套接字和多个用于每个已连接客户端的处理器套接字。
监听传入连接
当您开始监听端口时,您会创建一个带有用于传入连接的回调方法的套接字(这是引用您提到的示例)。这就是该端口号的唯一的监听器套接字:
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
这行代码告诉监听器在有新客户端连接时调用AcceptCallback
方法(即新连接回调),这个方法应该尽快完成工作,因为它会阻止其他传入连接。
创建专门的处理套接字
这也是为什么AcceptCallback
必须立即创建一个专门的"处理"套接字,并使用自己的后台数据回调方法 (ReadCallback
):
// inside AcceptCallback, we switch to the handler socket for communication
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state); // fired on a background thread
从那一刻起,每当您的新连接客户端接收到一些数据时,ReadCallback
方法就会被调用。
此外,在返回之前,AcceptCallback
需要再次调用listener.BeginAccept
,以继续监听新的传入连接:
// this is the same server socket we opened previously, which will now
// continue waiting for other client connections: it doesn't care about
// the actual data transmission between individual clients
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
MSDN示例中省略了这一部分,这意味着它只能接收单个连接。
接收数据
一旦从客户端接收到数据包,ReadCallback
方法将被调用。因此,在此数据回调方法中,您需要读取和处理接收到的数据,然后再次调用相同的BeginReceive
方法(再次使用ReadCallback
作为其数据回调方法)。
[编辑]
MSDN示例的问题在于它只允许单个客户端连接(只调用一次listener.BeginAccept
)。要允许多个并发连接,您需要使用handler.BeginReceive
创建一个接收套接字,然后调用listener.BeginAccept
以开始侦听新客户端。