Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 命名管道高效异步设计_Windows_Delphi_Winapi_Asynchronous_Named Pipes - Fatal编程技术网

Windows 命名管道高效异步设计

Windows 命名管道高效异步设计,windows,delphi,winapi,asynchronous,named-pipes,Windows,Delphi,Winapi,Asynchronous,Named Pipes,问题: 设计一个高效且非常快速的命名管道客户机-服务器框架 当前状态: 我已经有了经过战斗验证的生产测试框架。它是快速的,但是它在每个管道连接中使用一个线程,如果有许多客户端,线程的数量可能会非常快。我已经使用了智能线程池(事实上是任务池),可以根据需要进行扩展 我已经对管道使用了重叠模式,但随后我使用WaitForSingleObject或WaitForMultipleObjects进行阻塞,这就是为什么在服务器端每个连接需要一个线程的原因 所需解决方案: 客户机是很好的,但在服务器端,我希望

问题

设计一个高效且非常快速的命名管道客户机-服务器框架

当前状态

我已经有了经过战斗验证的生产测试框架。它是快速的,但是它在每个管道连接中使用一个线程,如果有许多客户端,线程的数量可能会非常快。我已经使用了智能线程池(事实上是任务池),可以根据需要进行扩展

我已经对管道使用了重叠模式,但随后我使用WaitForSingleObject或WaitForMultipleObjects进行阻塞,这就是为什么在服务器端每个连接需要一个线程的原因

所需解决方案:

客户机是很好的,但在服务器端,我希望每个客户机请求只使用一个线程,而不是每个连接。因此,我不会在客户端的整个生命周期(连接/断开连接)中使用一个线程,而是在每个任务中使用一个线程。所以,只有当客户机请求数据时,才需要

我在MSDN上看到了一个示例,它使用重叠结构的数组,然后使用WaitForMultipleObjects来等待它们。我觉得这个设计很糟糕。我在这里看到两个问题。首先,您必须维护一个数组,该数组可能会变得非常大,删除将非常昂贵。其次,您有很多事件,每个数组成员一个事件

我也看到了完成端口,比如和,但我看不出它们有多好

我想要的是做一些事情,他们调用回调例程 当操作完成时。这是一种真正的异步编程风格。但问题是ConnectNamedPipe不支持这一点,而且我看到线程需要处于可警报状态,您需要调用一些*Ex函数来实现这一点

那么如何才能最好地解决这样的问题呢?

以下是MSDN是如何做到这一点的:

我发现这种方法的问题是,如果限制为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请求时创建线程


若服务器必须处理64个以上的事件(读/写),那个么任何使用WaitForMultipleObjects的解决方案都将变得不可行。这就是Microsoft将IO完成端口引入Windows的原因。它可以使用最合适的线程数(通常是处理器/内核数)处理非常多的IO操作

IOCP的问题是很难实现正确的操作。隐藏的问题像矿场中的地雷一样扩散:[],[](第3.6节)。我建议使用一些框架。小谷歌为Delphi开发人员提供了一些建议。也许还有其他人


在这一点上,如果这意味着编码自己的IOCP实现,我将忽略命名管道的要求。这不值得悲伤。

我认为您忽略的是,在任何给定时间,您只需要几个侦听命名管道实例。连接管道实例后,可以剥离该实例并创建新的侦听实例来替换它

使用侦听命名管道实例的
最大\u WAIT\u对象
(或更少),可以使用
WaitForMultipleObjectsEx
拥有一个专用于侦听的线程。同一线程还可以使用
ReadFileEx
writefilex
和APCs处理其余的I/O。工作线程将APC排队到I/O线程以启动I/O,I/O线程可以使用任务池返回结果(以及让工作线程知道新连接)

I/O线程主函数如下所示:

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;
create_events();
对于(index=0;index=等待对象0&&
结果<等待对象0+最大等待对象)
{
索引=结果-等待对象0;
重置事件(连接事件[索引]);
if(GetOverlappedResult(
connect_句柄[索引],&connect_重叠[索引],
&字节(u计数,FALSE))
{
err=错误\成功;
}
其他的
{
err=GetLastError();
}
连接管道完成(索引、错误);
继续;
}
其他的
{
失败();
}
}
唯一真正复杂的是,当您调用
ConnectNamedPipe
时,它可能会返回
ERROR\u PIPE\u CONNECTED
,以指示