CallNamedPipe和TransactNamedPipe不起作用

时间:2017-03-06 13:50:53

标签: c winapi ipc named-pipes

我想向服务器发送消息并使用命名管道读取它。当我使用WriteFile函数时,消息到达服务器,但TransactNamedPipe失败,错误230(ERROR_BAD_PIPE),CallNamedPipe失败,错误87(INVALID_PARAMETER)或231(PIPE_BUSY)。我已经尝试过MSDN示例,很多其他的东西,但仍然没有结果。请帮忙。

客户端:

#include <windows.h> 
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string>

#define BUFSIZE 512

int _tmain(int argc, TCHAR *argv[])
{
    OVERLAPPED ov;
    ZeroMemory(&ov, sizeof(OVERLAPPED));

    HANDLE hPipe;
    // Try to open a named pipe; wait for it, if necessary. 
    while (1)
    {
        hPipe = CreateFile(
            L"\\\\.\\pipe\\PipeTest",   // pipe name 
            GENERIC_READ |  // read and write access 
            GENERIC_WRITE,
            0,              // no sharing 
            NULL,           // default security attributes
            OPEN_EXISTING,  // opens existing pipe 
            FILE_FLAG_OVERLAPPED,             
            NULL);          // no template file 

                            // Break if the pipe handle is valid. 
        if (hPipe != INVALID_HANDLE_VALUE)
            break;

        DWORD lastErr = GetLastError();

        // Exit if an error other than ERROR_PIPE_BUSY occurs. 
        if (GetLastError() != ERROR_PIPE_BUSY)
        {
            printf("Could not open pipe\n");
            return 0;
        }

        // All pipe instances are busy, so wait for 2 seconds. 
        if (!WaitNamedPipe(L"\\\\.\\pipe\\PipeTest", 2000))
        {
            printf("Could not open pipe\n");
            return 0;
        }
    }

    std::wstring s;
    s.resize(1024);
    DWORD cbRead;

    BOOL fSuccess = TransactNamedPipe(
        hPipe,                  // pipe handle 
        L"Hello",              // message to server
        sizeof(wchar_t) * 5, // message length
        &s[0],
        s.size() * sizeof(wchar_t),
        &cbRead,                // bytes read
        &ov);                  // not overlapped 

    DWORD lastErr = GetLastError();
    GetOverlappedResult(hPipe, &ov, &cbRead, TRUE);
    DWORD lastErr2 = GetLastError();

    CloseHandle(hPipe);

    return 0;
}

服务器:

#include <iostream>
#include <string>
#include <Windows.h>

const std::wstring pipeName = L"\\\\.\\pipe\\PipeTest";

int main(void)
{
    HANDLE hPipe;
    wchar_t buffer[256];
    DWORD dwRead;

    OVERLAPPED ov;
    ZeroMemory(&ov, sizeof(OVERLAPPED));

    hPipe = CreateNamedPipe(pipeName.c_str(),
        PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,   // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
        PIPE_WAIT,
        1,
        1024 * 16,
        1024 * 16,
        NMPWAIT_USE_DEFAULT_WAIT,
        NULL);

    if (hPipe != INVALID_HANDLE_VALUE)
    {
        if (ConnectNamedPipe(hPipe, &ov) != FALSE)   // wait for someone to connect to the pipe
        {
            while (ReadFile(hPipe, buffer, 255, &dwRead, &ov) != FALSE)
            {
                WriteFile(hPipe, L"lalala", 6 * sizeof(wchar_t), &dwRead, &ov);

                DWORD lastErr1 = GetLastError();
                GetOverlappedResult(hPipe, &ov, &dwRead, TRUE);
                DWORD lastrr2 = GetLastError();

                printf("%s", buffer);
            }
        }

        DisconnectNamedPipe(hPipe);
    }

    return 0;
}

1 个答案:

答案 0 :(得分:1)

如果您阅读TransactNamedPipe

  如果服务器没有创建管道,则

TransactNamedPipe会失败   消息类型管道或管道句柄未处于消息读取模式。

CallNamedPipe

  

调用CallNamedPipe相当于调用CreateFile(或   WaitNamedPipe,如果CreateFile无法立即打开管道,    TransactNamedPipe 和CloseHandle函数

所以这个函数只能用于消息型管道

但是当您创建服务器管道时,使用PIPE_TYPE_BYTE | PIPE_READMODE_BYTE 所以CallNamedPipe和/或TransactNamedPipe必须失败。

您需要使用ReadFile / WriteFile。或创建带有标记PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE的服务器并调用SetNamedPipeHandleState以获取客户端句柄以设置其消息读取模式(使用PIPE_READMODE_MESSAGE