C++ 使用命名管道WinAPI的异步I/O

C++ 使用命名管道WinAPI的异步I/O,c++,winapi,asynchronous,named-pipes,C++,Winapi,Asynchronous,Named Pipes,好的,我已经问了一些关于我想做的事情的不同方面的问题。这一次,我只是从一个命名管道中读取数据,遇到了一些大问题。我想我已经收集了足够的信息,如果我能正确设置的话,我有可能完成我正在进行的项目。我将在下面列出所有相关代码,但我的任务是:从我没有编写的程序中(连续地)读取输出并将其发布到WinAPI。所以我的问题是,我刚刚从匿名管道切换到命名管道,我在尝试正确设置它们以便检索信息时遇到了问题。我有一个基于MSDN示例的框架设置 #define WAIT_TIME 2 // 2s #define IN

好的,我已经问了一些关于我想做的事情的不同方面的问题。这一次,我只是从一个命名管道中读取数据,遇到了一些大问题。我想我已经收集了足够的信息,如果我能正确设置的话,我有可能完成我正在进行的项目。我将在下面列出所有相关代码,但我的任务是:从我没有编写的程序中(连续地)读取输出并将其发布到WinAPI。所以我的问题是,我刚刚从匿名管道切换到命名管道,我在尝试正确设置它们以便检索信息时遇到了问题。我有一个基于MSDN示例的框架设置

#define WAIT_TIME 2 // 2s
#define INSTANCES 4 // Number of threads
#define CONNECT_STATE 0
#define READ_STATE 1
#define WRITE_STATE 2
#define WORLDRD 0
#define WORLDWR 1
#define WORLDINRD 2
#define WORLDINWR 3
#define BUFSIZE 0x1000 // Buffer size 4096 (in bytes)
#define PIPE_TIMEOUT 0x1388 // Timeout 5000 (in ms)

void Arc_Redirect::createProcesses()
{
TCHAR programName[]=TEXT("EXEC_PROGRAM.exe");
PROCESS_INFORMATION pi; 
STARTUPINFO si;
BOOL bSuccess = FALSE; 

ZeroMemory(hEvents,(sizeof(hEvents)*INSTANCES));
ZeroMemory(outStd,(sizeof(PIPE_HANDLES)*INSTANCES));

// Prep pipes
for(int i=0;i<INSTANCES;i++)
{
    hEvents[i] = ::CreateEvent(NULL, TRUE, FALSE, NULL);

    if(hEvents[i] == NULL)
        throw "Could not init program!";

    outStd[i].o1.hEvent = hEvents[i];

    outStd[i].hPipeInst = ::CreateNamedPipe(
        TEXT("\\\\.\\pipe\\arcworld"), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
        PIPE_UNLIMITED_INSTANCES, BUFSIZE*sizeof(TCHAR), BUFSIZE*sizeof(TCHAR), PIPE_TIMEOUT, NULL);

    if(outStd[i].hPipeInst == INVALID_HANDLE_VALUE)
        throw "Could not init program!";

    outStd[i].pendingIO = getState(outStd[i].hPipeInst,&outStd[i].o1);

    outStd[i].dwState = outStd[i].pendingIO ?
        CONNECT_STATE : READ_STATE;
}

// Set stuff up
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION));
ZeroMemory( &si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO); 
si.hStdError = outStd[WORLDRD].hPipeInst;
si.hStdOutput = outStd[WORLDRD].hPipeInst;
si.hStdInput = outStd[WORLDINWR].hPipeInst;
si.dwFlags |= STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES|FILE_FLAG_OVERLAPPED;

    // Start our process with the si info
CreateProcess(programName,NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
}

BOOL Arc_Redirect::getState(HANDLE hPipe, LPOVERLAPPED lpo)
{
    BOOL connected, pendingIO = FALSE;

    // Overlap connection for this pipe
    connected = ::ConnectNamedPipe(hPipe,lpo);

    if(connected)
        throw "ConnectNamedPipe(); failed!";

    switch(GetLastError())
    {
        case ERROR_IO_PENDING:
            pendingIO = TRUE;
        break;
        case ERROR_PIPE_CONNECTED:
            if(SetEvent(lpo->hEvent))
                break;  
        default:
            throw "ConnectNamedPipe(); failed!";
        break;
    }

    return pendingIO;
}
从这里开始,我有点迷路了。我不知道该去哪里。我尝试在MSDN示例中使用该循环,但对于我要做的事情,它没有正常工作。我需要获取管道的读取端并检索信息(再次,连续地),同时打开写入端,以便在需要写入时使用。有人有什么想法吗?我一直在尝试像处理匿名管道一样处理ReadFile(),但它似乎没有以相同的方式工作


另外,请注意:代码有点草率,因为我一直在使用它,所以我道歉。在我让它正常运行之后,我肯定会清理它。

在linux世界中,一个程序可以通过write/fwrite调用写入命名管道,另一个程序可以通过read/frad()读取它


在读/写操作中必须使用命名管道的完整路径。

是否尝试在
CreateNamedPipe
调用中传递
pipe\u NOWAIT
而不是
pipe\u WAIT
?这将允许
ReadFile
WriteFile
非阻塞


或者,您是否尝试过使用异步IO?您正在传递
文件\u标志\u OVERLAPPED
标志,因此这应该可以工作。如果你试过,你遇到了什么问题?

你应该有两个重叠的结构,一个用于阅读,一个用于写作。此外,当您想要关闭管道时,每个管道需要一个事件句柄,当您想要中止所有(并关闭应用程序)时,还需要一个事件句柄。对于所有管道当前涉及的每个操作,可以有一个WaitForMultipleObjects,或者在两个线程中分别读取和写入,每个线程中有一个WFMO。我将只使用一个线程,因为关闭管道会更简单(否则您需要在管道句柄上进行一些引用计数,并仅在引用计数降至零时关闭它)

当您获得一个事件时,然后处理它,并在刚刚处理的事件之后的数组中的所有句柄上用0秒时间尝试WFMO。这样就不会有管道饿死。当0秒WFMO过去时,从一开始重复正常WFMO


如果需要高并发性,则在单独的线程中处理事件,并省略WFMO中当前的处理句柄。但是,跟踪所有句柄会变得有点复杂。

ReadFile的具体问题是什么?命名管道和匿名管道打开后工作原理相同。出于我的目的,我已切换回匿名管道,但是,这两个管道似乎存在相同的问题。它需要等到数据传输结束后才能发送任何数据,所以我将继续处理它。
typedef struct
{
    HANDLE hPipeInst;
    OVERLAPPED o1;
    TCHAR chReq[BUFSIZE];
    TCHAR chReply[BUFSIZE];
    DWORD dwRead;
    DWORD dwWritten;
    DWORD dwState;
    DWORD cbRet;
    BOOL pendingIO;
} PIPE_HANDLES, *LPSTDPIPE;