2010-07-12 92 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標誌,所以這應該工作。如果你嘗試過,你遇到了什麼問題?