命名管道操作

管道服务器首次调用 CreateNamedPipe 函数时,它使用 nMaxInstances 参数指定可以同时存在的管道实例的最大数目。 服务器可以重复调用 CreateNamedPipe 以创建管道的其他实例,只要它不超过最大实例数。 如果函数成功,则每次调用都会返回一个指向命名管道实例的服务器端的句柄。

管道服务器创建管道实例后,管道客户端可以通过调用 CreateFileCallNamedPipe 函数连接到该实例。 如果管道实例可用, CreateFile 会将句柄返回到管道实例的客户端。 如果没有可用的管道实例,管道客户端可以使用 WaitNamedPipe 函数等待管道变得可用。

管道服务器可以通过调用 ConnectNamedPipe 函数来确定管道客户端何时连接到管道实例。 如果管道句柄处于阻止等待模式,则在连接客户端之前, ConnectNamedPipe 不会返回。

除了 CallNamedPipe 之外,管道客户端和服务器还可以调用多个函数之一,以便从命名管道读取和写入。 这些函数的行为取决于管道的类型以及指定的管道句柄的生效模式,如下所示:

  • ReadFileWriteFile 函数可与字节类型管道或消息类型管道一起使用。
  • 如果为重叠操作打开了管道句柄,ReadFileEx 和 WriteFileEx 函数可以与字节类型管道或消息类型管道一起使用。
  • PeekNamedPipe 函数可用于读取,而无需删除字节类型管道或消息类型管道的内容。 PeekNamedPipe 还可以返回有关管道实例的其他信息。
  • 如果将调用进程的管道句柄设置为消息读取模式,则 TransactNamedPipe 函数可与消息类型的双工管道一起使用。 函数在单个操作中写入请求消息并读取回复消息,从而提高网络性能。

在管道客户端启动之前,管道服务器不应执行阻止读取操作。 否则,可能会出现争用情况。 当初始化代码(如 C 运行时库的初始化代码)需要锁定和检查继承的句柄时,通常会发生这种情况。

当客户端和服务器使用完管道实例时,服务器应首先调用 FlushFileBuffers 函数,以确保客户端读取写入管道的所有字节或消息。 在客户端从管道读取所有数据之前,FlushFileBuffers 不会返回。 然后,服务器调用 DisconnectNamedPipe 函数以关闭与管道客户端的连接。 此函数会使客户端的句柄无效(如果尚未关闭)。 管道中的任何未读数据将被丢弃。 客户端断开连接后,服务器调用 CloseHandle 函数以关闭其管道实例的句柄。 或者,服务器可以使用 ConnectNamedPipe 使新客户端能够连接到管道的此实例。

进程可以通过调用 GetNamedPipeInfo 函数来检索有关命名管道的信息,该函数返回管道的类型、输入和输出缓冲区的大小以及可以创建的管道实例的最大数目。 GetNamedPipeHandleState 函数报告管道句柄的读取和等待模式、管道实例的当前数目,以及通过网络通信的管道的其他信息。 SetNamedPipeHandleState 函数设置管道句柄的读取模式和等待模式。 对于与远程服务器通信的管道客户端,函数还控制要收集的最大字节数或传输消息之前的最大等待时间, (假设客户端的句柄未在启用) 的写通模式的情况下打开。