【问题标题】:Asynchronous I/O with Named Pipes WinAPI使用命名管道 WinAPI 的异步 I/O
【发布时间】:2010-07-12 00:10:07
【问题描述】:

好的,我已经问了几个关于尝试完成我想做的事情的不同方面的问题。这次我只是从命名管道中读取数据时遇到了大问题。我想我已经获得了足够的信息来完成我正在做的项目,如果我能正确设置的话。我将在下面包含所有相关代码,但我的任务是:从我没有编写的程序中读取输出(连续)并将其发布到 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;
}

outStd[INSTANCES] 被定义为下面的 PIPE_HANDLES(一个自定义结构)

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;

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

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

【问题讨论】:

  • ReadFile 到底有什么问题?命名管道和匿名管道打开后的工作方式相同。
  • 出于我的目的,我已切换回匿名管道,但是,这似乎是两个相同的问题。它需要等到数据传输结束才能发送任何数据,所以我将继续研究它。

标签: c++ winapi asynchronous named-pipes


【解决方案1】:

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

当您收到一个事件时,然后对其进行处理,然后在您刚刚处理的事件之后的数组中的所有句柄上尝试 WFMO,时间为 0 秒。这样,任何管道都不会饿死。当 0 秒 WFMO 过去时,从头开始重复正常的 WFMO。

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

【讨论】:

    【解决方案2】:

    您是否尝试在 CreateNamedPipe 调用中传递 PIPE_NOWAIT 而不是 PIPE_WAIT?这将允许ReadFileWriteFile 成为非阻塞的。

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-29
        • 2013-06-19
        • 1970-01-01
        • 2010-09-08
        相关资源
        最近更新 更多