【发布时间】:2013-07-23 09:01:53
【问题描述】:
问题:
设计一个高效且非常快速的命名管道客户端服务器框架。
当前状态:
我已经拥有经过实战验证的生产测试框架。它很快,但是每个管道连接使用一个线程,如果有很多客户端,线程数可能很快就会很高。我已经使用了可以根据需要扩展的智能线程池(实际上是任务池)。
我已经对管道使用了 OVERLAPED 模式,但随后我使用 WaitForSingleObject 或 WaitForMultipleObjects 进行阻塞,这就是为什么我需要在服务器端每个连接一个线程
所需的解决方案:
客户端很好,但在服务器端,我想只为每个客户端请求而不是每个连接使用一个线程。因此,我不会在客户端的整个生命周期(连接/断开连接)中使用一个线程,而是每个任务使用一个线程。所以只有当客户端请求数据时才可以。
我在 MSDN 上看到一个示例,它使用 OVERLAPED 结构数组,然后使用 WaitForMultipleObjects 等待它们。我觉得这是一个糟糕的设计。我在这里看到两个问题。首先,您必须维护一个可以变得非常大的数组,并且删除的成本很高。其次,您有很多事件,每个数组成员都有一个。
我还看到了完成端口,例如 CreateIoCompletionPort 和 GetQueuedCompletionStatus,但我看不出它们有什么更好的地方。
我想要的是 ReadFileEx 和 WriteFileEx 做的事情,他们调用回调例程 当操作完成时。这是一种真正的异步编程风格。但问题是 ConnectNamedPipe 不支持它,而且我看到线程需要处于警报状态,您需要调用一些 *Ex 函数来实现它。
那么如何最好地解决这样的问题?
这是 MSDN 的做法:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365603(v=vs.85).aspx
我在这种方法中看到的问题是,如果WaitForMultipleObjects 的限制为 64 个句柄,我看不到如何同时连接 100 个客户端。当然我可以在每次请求后断开管道,但我的想法是像在 TCP 服务器中一样拥有一个永久的客户端连接,并在整个生命周期中跟踪客户端,每个客户端都有唯一的 ID 和客户端特定的数据。
理想的伪代码应该是这样的:
repeat
// wait for the connection or for one client to send data
Result = ConnectNamedPipe or ReadFile or Disconnect;
case Result of
CONNECTED: CreateNewClient; // we create a new client
DATA: AssignWorkerThread; // here we process client request in a thread
DISCONNECT: CleanupAndDeleteClient // release the client object and data
end;
until Aborted;
这样我们就只有一个监听线程来接受connect/disconnect/onData事件。线程池(工作线程)只处理实际请求。这样 5 个工作线程就可以为许多连接的客户端提供服务。
附: 我当前的代码应该不重要。我在 Delphi 中编写代码,但它是纯 WinAPI,所以语言无关紧要。
编辑:
目前 IOCP 看起来像解决方案:
I/O 完成端口为 在多处理器上处理多个异步 I/O 请求 系统。当一个进程创建一个 I/O 完成端口时,系统 为唯一目的是的请求创建一个关联的队列对象 为这些请求提供服务。处理许多并发的进程 异步 I/O 请求可以通过以下方式更快、更有效地做到这一点 结合预分配线程使用 I/O 完成端口 池而不是在线程收到 I/O 请求时创建线程。
【问题讨论】:
-
另请注意
WaitForMultipleObject有 64 个句柄的限制 (MAXIMUM_WAIT_OBJECTS)! -
删除并不昂贵。那有什么意思?我在重叠结构上投票支持 WFMO。我看不出有什么不好的。只需要在等待数组中再添加一个事件,如果数组需要调整,或者完全中止正在进行中,它将停止等待。
-
@Dealeticus:动态数组的选择成本很高。如果删除中间的项目,则必须移动它后面的所有项目。这是编程结构 101 :) 好的,如果您有 100 个以下的项目,它不会显示。但我可以连接 100 多个客户端。
-
@Jochen Kalmbach:那会杀死那个实现:(
-
谁投票赞成关闭? 3 票赞成关闭对我来说是一个完全有效的问题。对这个问题的 6 个赞成票和两个最爱证实了这一点。堆栈溢出一天比一天陌生。
标签: windows delphi winapi asynchronous named-pipes