简体   繁体   English

写入时全双工命名管道锁定

[英]Full duplex named pipe lockup when written to

I'm trying to use one NamedPipe for bi-direction IPC.我正在尝试使用一个 NamedPipe 进行双向 IPC。 In my mind (and I can't find more information on MSDN), one full-duplex pipe would be sufficient.在我看来(我在 MSDN 上找不到更多信息),一个全双工管道就足够了。 Here's my code.这是我的代码。

//Compiled with these commands during my test:
//g++ -DCLIENT -o client.exe xxx.cpp
//g++ -DSERVER -o server.exe xxx.cpp

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI ReadingThread(LPVOID a)
{
    HANDLE pipe = (HANDLE)a;
    BOOL result;
    char buffer[256];
    DWORD numBytesRead;
    while (true)
    {
        result = ReadFile(pipe, buffer, sizeof(buffer) - 1, &numBytesRead, NULL);

        if (result)
        {
            buffer[numBytesRead] = 0;
            cout << "[Thread] Number of bytes read: " << numBytesRead << endl;
            cout << "[Thread] Message: " << endl
                 << buffer << endl
                 << endl;
        }
        else
        {
            cout << "[Thread] Failed to read data from the pipe. err=" << GetLastError() << endl;
            break;
        }
    }
    return 0;
}

int main(int argc, const char **argv)
{
#ifdef CLIENT
    cout << "[Main] Connecting to pipe..." << endl;
    HANDLE pipe = CreateFileA("\\\\.\\pipe\\PipeTest", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
    cout << "[Main] Creating an instance of a named pipe..." << endl;
    HANDLE pipe = CreateNamedPipeA("\\\\.\\pipe\\PipeTest", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 1, 0, 0, 0, NULL);
#endif

    if (pipe == NULL || pipe == INVALID_HANDLE_VALUE)
    {
        cout << "[Main] Failed to acquire pipe handle." << endl;
        return 1;
    }

#ifdef CLIENT
#else
    cout << "[Server] Waiting for a client to connect to the pipe..." << endl;

    BOOL result = ConnectNamedPipe(pipe, NULL);
    if (!result)
    {
        cout << "[Server] Failed to make connection on named pipe." << endl;
        CloseHandle(pipe);
        return 1;
    }
    cout << "[Server] Client is here!" << endl;
    {
        const char *buf = "Hello pipe!\n";
        WriteFile(pipe, buf, strnlen(buf, 30), 0, 0);
    }
#endif

    CreateThread(0, 0, ReadingThread, pipe, 0, 0);
    cout << "[Main] Ready to send data." << endl;

    while (true)
    {
        char buffer[128];
        DWORD numBytesWritten = 0;
        BOOL result;

        cin >> buffer;
        if (!strcmp(buffer, "q"))
        {
            break;
        }
        cout << "[Main] Writing data to pipe..." << endl;
        result = WriteFile(pipe, buffer, strnlen(buffer, _countof(buffer)), &numBytesWritten, 0);
        if (result)
        {
            cout << "[Main] Written " << numBytesWritten << " bytes to the pipe." << endl;
        }
        else
        {
            cout << "[Main] Failed to write data to the pipe. err=" << GetLastError() << endl;
        }
    }
    CloseHandle(pipe);
    cout << "[Main] Done." << endl;
    return 0;
}

I can get the "Hello pipe!"我可以得到“你好管道!” message from server-side to client-side.从服务器端到客户端的消息。 And I'm expecting to type some string on either program's terminal and press enter, and see it on the other side.我希望在任一程序的终端上输入一些字符串并按回车键,然后在另一侧看到它。

However after the hello message, both program will stuck on the WriteFile call.然而,在 hello 消息之后,两个程序都将停留在WriteFile调用上。 Meanwhile the thread is stuck at the ReadFile call.同时,线程卡在ReadFile调用处。 How can I make it work, or did I left something out?我怎样才能让它工作,或者我遗漏了什么?

when file created for synchronous I/O (flag FO_SYNCHRONOUS_IO present in FILE_OBJECT ) all I/O operations on file is serialized - new operation will be wait in I/O manager before passed to driver, until current(if exist) not complete.当为同步 I/O 创建文件( FILE_OBJECT存在标志FO_SYNCHRONOUS_IO )时,文件上的所有I/O 操作都被序列化- 新操作将在 I/O 管理器中等待,然后FO_SYNCHRONOUS_IO驱动程序,直到当前(如果存在)未完成。 in concurrent can execute only single I/O request.在并发中只能执行单个 I/O 请求。 if we do blocked read in dedicated thread - all another I/O request on this file will be blocked until read not complete.如果我们在专用线程中阻止读取 - 此文件上的所有其他 I/O 请求将被阻止,直到读取未完成。 this related not only to write.这不仅与写作有关。 even query file name/attributes will block here.甚至查询文件名/属性也会在此处阻塞。 as result render reading in separate not help here - we block on first write attemp.结果在这里单独渲染读取没有帮助 - 我们阻止第一次写入尝试。 solution here use asynchronous files - this let any count of I/O operation execute in concurrent.这里的解决方案使用异步文件 - 这让任何数量的 I/O 操作并发执行。

Named Pipes in Windows are HALF DUPLEX. Windows 中的命名管道是半双工。 As demonstrated on Windows 10. The MSDN Documentation is Wrong.如 Windows 10 所示。MSDN 文档是错误的。 A request has been submitted to Microsoft to correct their documentation.已向 Microsoft 提交更正其文档的请求。

While a pipe can be opened on the client to be "Generic Read | Generic Write" you can NOT do both at the same time.虽然可以在客户端上将管道打开为“通用读取 | 通用写入”,但您不能同时执行这两项操作。

And Overlapped IO submitted after the First Overlapped IO will break the pipe.而在First Overlapped IO之后提交的Overlapped IO会破坏管道。

You can submit overlapped io.您可以提交重叠的 io。 Then Wait for it to finish.然后等待它完成。 Then submit the next overlapped io.然后提交下一个重叠的io。 You can not simultaneously Submit overlapped Reads AND overlapped Writes.您不能同时提交重叠读取和重叠写入。

This is by definition, "Half Duplex".这就是定义,“半双工”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM