2010-07-12 62 views
2

好的,我问了几个关于试图完成我想要做的事情的不同方面的问题。这一次,我刚刚从一个命名管道读取大问题。我认为我已经收集了足够的信息来完成我正在研究的项目,如果我可以正确设置的话。我将在下面列出所有相关代码,但我的任务是这样的:从一个程序中读取输出(连续),我做了而不是写入并将其发布到WinAPI。所以我的问题是,我刚从匿名管道切换到命名管道,我有问题试图正确设置它们,所以我可以检索信息。我有一个基于MSDN示例的框架设置。带有命名管道的异步I/O WinAPI

#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 [启动]被定义为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(),就像我使用匿名管道做的一样,但它似乎没有以同样的方式工作。

此外,请注意:代码有点马虎,因为我一直在使用它,所以我很抱歉。我一定会清理它后,我得到这个功能正常。

+0

使用ReadFile的问题到底是什么?命名管道和匿名管道一旦打开就可以工作。 – 2010-07-16 07:22:07

+0

为了达到我的目的,我已经切换回匿名管道,但是,这两者似乎都是相同的问题。它需要等到数据传输结束才能发送任何数据,因此我将继续研究它。 – RageD 2010-07-16 13:16:00

回答

1

你应该有两个OVERLAPPED结构,一个用于阅读,另一个用于写作。当你想关闭管道时,你还需要每个管道有一个事件句柄,而当你想中止所有的(关闭应用程序)时,还需要一个事件句柄。对于所有管道当前涉及的每个操作,您可以有一个WaitForMultipleObjects,或者分别从两个线程中分别读取一个WFMO。我只用一个线程去,因为关闭管道比较简单(否则你需要在管道手柄上有一些引用计数,并且只有当引用计数下降到零时关闭它)。

当你得到一个事件然后处理它,然后在你刚处理的数组之后的数组中的所有句柄上用0秒的时间尝试WFMO。这样,没有管道会饿死。当0秒WFMO从头开始经过正常的WFMO时。

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

0

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

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

1

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

另外,你有没有尝试过使用异步IO?你通过FILE_FLAG_OVERLAPPED标志,所以这应该工作。如果你尝试过,你遇到了什么问题?