异步服务器套接字多客户端

16

我一直在使用msdn上发布的以下代码:

http://msdn.microsoft.com/en-us/library/fx6588te.aspx

我知道在应用程序等待新客户端时,服务器应用程序不会被阻塞。

但是,这个应用程序(或套接字)能处理多个并发请求吗?

  • 如果客户端A和B同时连接会发生什么?

  • 如果客户端A连接并且处理它的请求需要5秒钟,如果客户端B在一秒钟后连接,那么它必须等待客户端A完成才能开始处理吗?

  • 还是客户端A和客户端B的请求将同时处理?

我已经通过在套接字侦听器代码中的接收/发送数据之间放置Thread.Sleep(n)命令进行了一些测试。然后,我可以向套接字发送多个请求,并且它们似乎被处理。但是套接字始终在相同的线程ID上处理它们 - 这使我相信它实际上并没有同时进行。

特别是考虑到微软的描述,这个应用程序只是在等待新连接时不会被阻塞 - 这是否意味着它可以处理并发连接?


实际上,该页面指出服务器应用程序的执行在等待客户端连接时不会被挂起,因为所有调用都是使用异步回调完成的,这意味着您的主线程在等待连接或数据时不会被阻塞。但是,它确实可以同时在多个线程上接收数据,尽管对于单个传入连接只能有一个“接受”回调处于活动状态(这意味着在接受连接时必须快速完成工作)。 - vgru
嗨,RemotecUK,你能否发布你更新后的接受多个连接的代码?我也使用了MSDN的示例,需要处理多个连接。请帮忙。 - Vijay Choudhary
2个回答

34

[更新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以开始侦听新客户端。


谢谢您的回复!你今天为我挽救了冠军联赛:)。我在调用新连接“BeginAccept”之前调用了“BeginReceive”,这导致了问题。 - Andre Hofmeister
嗨Groo,你能否发布接受多个连接的最新MSDN示例代码?我需要它。请帮忙。 - Vijay Choudhary
1
@daniel:这实际上是用于接受多个连接的代码。每当建立新连接时,AcceptCallback 就会被调用,并在其中调用 listener.BeginAccept 返回一个专用于该连接的 Socket(然后与其自己的 ReadCallback 处理程序相关联)。如果您有特定的用例,请发布一个带有详细信息的单独问题。 - vgru
嗨,Groo,请查看我的这个问题http://stackoverflow.com/questions/25404114/asynchronous-server-socket-not-getting-data,并帮忙。谢谢。 - Vijay Choudhary

-1
每个套接字都有一个关联的监听队列。这将包含待处理/部分接受的传入连接。最大挂起连接数可以在listen() API中以编程方式定义,这在本例中就是'listener.Listen(100)'。在这里将其设置为100后,套接字'listener'可以在监听队列中拥有150(=2*100/2)个挂起连接。

12
2 * 100 / 2 = 150?绝不可能。 - Andre Hofmeister

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接