创建命名管道错误

CMo*_*use 0 c++ windows winapi named-pipes

我正在创建一个命名管道并使用一个函数来执行此操作.这是代码:

HANDLE              tProviderPipe(INVALID_HANDLE_VALUE);
SECURITY_ATTRIBUTES tSecurityAttributes;

tSecurityAttributes.nLength = sizeof(tSecurityAttributes);
tSecurityAttributes.bInheritHandle = FALSE;
tSecurityAttributes.lpSecurityDescriptor = NULL;
while (1)
{
    tProviderPipe = ::CreateNamedPipe(L"\\\\.\\pipe\\MyPipe",
                                      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
                                      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                                      1,
                                      128,
                                      128,
                                      5000,
                                      &tSecurityAttributes);

    if (INVALID_HANDLE_VALUE != tProviderPipe)
    {
        DWORD lLastStatus(GetLastError());
        OHTRACE(Trace::eTAlways, L"Pipe Status: " << (unsigned int)lLastStatus);
        break;
    }
    if (ERROR_PIPE_BUSY != GetLastError())
    {
        DWORD lLastStatus(GetLastError());
        OHTRACE(Trace::eTAlways, L"Pipe Status: " << (unsigned int)lLastStatus);
        break;
    }
    if (!WaitNamedPipe(L"MyPipe", 20000))
    {
        DWORD lLastStatus(GetLastError());
        OHTRACE(Trace::eTAlways, L"WPipe Status: " << (unsigned int)lLastStatus);
    }
Run Code Online (Sandbox Code Playgroud)

调用此函数时,管道创建失败,错误代码为231(即管道忙).我不明白为什么管道繁忙以及创建管道的正确方法是什么?在开始创建管道之前,应该检查和预检查的内容是什么?

Rem*_*eau 6

你展示的代码都是错的.

这个检查:

if (INVALID_HANDLE_VALUE != tProviderPipe)
Run Code Online (Sandbox Code Playgroud)

需要使用==而不是!=.如果CreateNamedPipe() 成功,您的代码将失败.

这个检查:

if (ERROR_PIPE_BUSY != GetLastError())
Run Code Online (Sandbox Code Playgroud)

需要删除.首先,它在错误的地方.GetLastError()仅在CreateNamedPipe() 失败时有效.完成上述==修复后,成功GetLastError()后将永远不会ERROR_PIPE_BUSY(或任何其他有意义的值)CreateNamedPipe().其次,如果你将它移动到if正在检查的那个,tProviderPipe那么它就变得多余了,因为它记录了那里已经记录的相同信息.

这个检查:

if (!WaitNamedPipe(L"MyPipe", 20000))
Run Code Online (Sandbox Code Playgroud)

还需要删除.首先,您传递的是错误的管道名称格式.其次,它用于命名管道客户端在调用之前调用CreateFile()(或者如果CreateFile()失败ERROR_PIPE_BUSY).不要在命名管道服务器中调用它.您打算调用ConnectNamedPipe(),等待客户端连接到您正在创建的服务器管道.

请查看MSDN 上的命名管道服务器示例.

尝试更像这样的东西:

HANDLE tProviderPipe = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES tSecurityAttributes;
OVERLAPPED ov = {};
DWORD lLastStatus;

ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!ov.hEvent) {
    lLastStatus = GetLastError();
    OHTRACE(Trace::eTAlways, L"Pipe Event Create Error: " << (UINT)lLastStatus);
    return;
}

tSecurityAttributes.nLength = sizeof(tSecurityAttributes);
tSecurityAttributes.bInheritHandle = FALSE;
tSecurityAttributes.lpSecurityDescriptor = NULL;

while (1) {
    if (INVALID_HANDLE_VALUE == tProviderPipe) {
        tProviderPipe = ::CreateNamedPipe(L"\\\\.\\pipe\\MyPipe", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 128, 128, 5000, &tSecurityAttributes);
        if (INVALID_HANDLE_VALUE == tProviderPipe) {
            lLastStatus = GetLastError();
            OHTRACE(Trace::eTAlways, L"Pipe Create Error: " << (UINT)lLastStatus);
            break;
        }
    }

    if (!ConnectNamedPipe(tProviderPipe, &ov)) {
        lLastStatus = GetLastError();
        if (ERROR_IO_PENDING == lLastStatus) {
            if (WaitForSingleObject(ov.hEvent, 20000) != WAIT_OBJECT_0) {
                OHTRACE(Trace::eTAlways, L"Pipe not connected in 20 seconds");
                break;
            }
        }
        else if (ERROR_PIPE_CONNECTED != lLastStatus) {
            OHTRACE(Trace::eTAlways, L"Pipe Connect Error: " << (UINT)lLastStatus);
            continue;
        }
    }

    // use tProviderPipe as needed ...

    DisconnectNamedPipe(tProviderPipe);
}

if (INVALID_HANDLE_VALUE != tProviderPipe) {
    CloseHandle(tProviderPipe);
}

CloseHandle(ov.hEvent);
Run Code Online (Sandbox Code Playgroud)

  • @CMouse:您是否复制粘贴此答案中的代码,或者您是否手动更改了代码?如果是后者,请改为做前者. (3认同)