命名管道:连接命名管道返回ERROR_BROKEN_PIPE后的读取文件

Named pipe: ReadFile after ConnectNamedPipe return ERROR_BROKEN_PIPE

本文关键字:管道 读取 文件 PIPE ERROR 连接 返回 BROKEN      更新时间:2023-10-16

我重新激活了几个月前我确信曾经使用过的代码。它让我发疯,但现在不会了。我无法在其他问题中找到答案。

在服务器端,我使用

#define MAX_MESSAGE_LENGTH 1024
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE);
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
auto pipe_name = _T("\\.\pipe\") + _serviceName;
HANDLE pipe = CreateNamedPipe(
    pipe_name.c_str(),
    PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
    1, 
    MAX_MESSAGE_LENGTH, MAX_MESSAGE_LENGTH, // buffer lengths (advisory)
    0, // default timeout of 50ms when WaitNamedPipe uses NMPWAIT_USE_DEFAULT_WAIT
    &sa));

然后,线程等待具有ConnectNamedPipe的传入客户端。 ConnectNamedPipe块,直到客户端连接到

HANDLE pipe = CreateFile(
    pipe_name.c_str(),   // pipe name 
    GENERIC_READ |  // read and write access 
    GENERIC_WRITE,
    0,              // no sharing 
    NULL,           // default security attributes
    OPEN_EXISTING,  // opens existing pipe 
    FILE_ATTRIBUTE_NORMAL, // default attributes 
    NULL);         // no template file 

然后,服务器上的ConnectNamedPipe返回 TRUEGetLastError == 0 。但是,当它尝试调用ReadFile来读取管道上的传入数据时,ReadFile会立即返回FALSEGetLastError==ERROR_BROKEN_PIPE。在客户端,CreateFile返回GetLastError==231,"所有管道实例都繁忙"。虽然它是唯一的客户端!对 WaitNamedPipe(pipe, 2000) 的调用返回错误代码 121"信号量超时期限已过期"。增加 CreateNamedPipe 中允许的客户端数不会改变任何内容。

似乎在客户端尝试连接的那一刻,管道完全断开了。但是为什么?客户端和服务器在同一台计算机上运行,具有相同的用户甚至相同的会话。然后,对ConnectNamedPipe的另一个调用失败,GLE=232:"管道正在关闭"。

我还有其他SECURITY_ATTRIBUTES用于CreateNamedPipe,这将允许非提升的用户连接,但这没有区别。

我也尝试在客户端上使用CallNamedPipe,结果相同。

PathFileExists 是管道杀手!经过几个小时的尝试,我终于找到了破坏管道的原因:对管道名称上存在 PathFile 的简单调用!这是最近在客户端添加的,用于检查管道是否已创建。我看了一下代码更改,但我完全错过了。PathFileExists 正确返回 true 或 false,但似乎弄乱了管道(正如我所说,它无助于允许多个客户端连接)。唉!!