首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ 匿名管道實作:父子進程單向通訊完整範例

     編輯:VC 教學

匿名管道核心概念

  • 定義:一段共享記憶體,父進程 (管道伺服器) 建立,子進程 (管道客戶端) 連接,單向資料流。
  • 特性:僅限本機、父子進程關係、不支援網路、不支援非同步 I/O。
  • 句柄:CreatePipe 回傳讀取句柄 (hReadPipe) 與寫入句柄 (hWritePipe)。

API 簽章

BOOL CreatePipe(
    PHANDLE hReadPipe,          // 輸出:讀取句柄
    PHANDLE hWritePipe,         // 輸出:寫入句柄
    LPSECURITY_ATTRIBUTES lpPipeAttributes, // 安全屬性 (決定可否繼承)
    DWORD nSize                 // 緩衝區大小建議值 (0 = 預設)
);

句柄繼承機制

  1. SECURITY_ATTRIBUTES.bInheritHandle = TRUE → 建立的管道句柄可被子進程繼承。
  2. CreateProcess 參數 bInheritHandles = TRUE → 子進程繼承所有可繼承句柄。
  3. 父進程可用 DuplicateHandle 建立可/不可繼承的副本。

標準 I/O 重導向流程

父進程透過 SetStdHandle 將管道句柄指派給子進程的標準輸入/輸出/錯誤:

  • 父寫 → 子讀:父 SetStdHandle(STD_INPUT_HANDLE, hRead),子 GetStdHandle(STD_INPUT_HANDLE) → ReadFile。
  • 子寫 → 父讀:子 SetStdHandle(STD_OUTPUT_HANDLE, hWrite),父 ReadFile(hRead, ...)。

完整父進程代碼 (管道伺服器)

STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
CHAR ReadBuf[1024];
DWORD ReadNum;
HANDLE hRead, hWrite;

// 1. 建立管道 (允許句柄繼承)
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
BOOL bRet = CreatePipe(&hRead, &hWrite, &sa, 0);
if (!bRet) { printf("建立管道失敗: %d\n", GetLastError()); return; }
printf("管道建立成功。\n");

// 2. 保存原標準輸出,將管道寫入端設為子進程標準輸出
HANDLE hOldOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetStdHandle(STD_OUTPUT_HANDLE, hWrite);

// 3. 取得啟動資訊並建立子進程
GetStartupInfo(&si);
bRet = CreateProcess(
    NULL, _T("Client.exe"), NULL, NULL,
    TRUE,                    // 繼承句柄
    0, NULL, NULL, &si, &pi);
SetStdHandle(STD_OUTPUT_HANDLE, hOldOut);  // 還原父進程標準輸出

if (!bRet) { printf("建立子進程失敗: %d\n", GetLastError()); return; }
printf("子進程啟動成功 (PID=%d)。\n", pi.dwProcessId);

// 4. 關閉父進程不需要的寫入端 (關鍵!否則 ReadFile 不會遇到 EOF)
CloseHandle(hWrite);

// 5. 讀取管道資料直到 EOF
while (ReadFile(hRead, ReadBuf, sizeof(ReadBuf)-1, &ReadNum, NULL))
{
    if (ReadNum == 0) break;
    ReadBuf[ReadNum] = '\0';
    printf("收到子進程資料: %s", ReadBuf);
}

CloseHandle(hRead);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
printf("通訊結束。\n");

子進程代碼 (Client.exe)

int main()
{
    // 子進程繼承了父進程設定的標準輸出 (管道寫入端)
    // 直接用 printf / cout 輸出即自動寫入管道
    printf("子進程啟動,PID=%d\n", GetCurrentProcessId());
    for (int i = 1; i <= 5; i++)
    {
        printf("訊息 #%d 來自子進程\n", i);
        Sleep(500);
    }
    printf("子進程結束。\n");
    return 0;  // 進程結束自動關閉標準輸出句柄,父進程 ReadFile 返回 0 (EOF)
}

關鍵點總結

關鍵步驟說明
CreatePipe + bInheritHandle=TRUE建立可繼承的管道句柄對
SetStdHandle(STD_OUTPUT_HANDLE, hWrite)將管道寫入端綁定為子進程標準輸出
CreateProcess(..., TRUE, ...)啟用句柄繼承建立子進程
父進程 CloseHandle(hWrite)必須關閉寫入端,否則父進程 ReadFile 永不遇到 EOF
ReadFile 迴圈讀取直到返回 FALSE 或 ReadNum=0 (EOF)

限制與替代方案

  • 單向、本機、父子限制 → 改用命名管道 (CreateNamedPipe) 支援雙向、跨進程、跨網路。
  • 非同步 I/O 需求 → 命名管道支援 FILE_FLAG_OVERLAPPED。
  • 高效能本機 IPC → 共享記憶體 (CreateFileMapping) + 事件同步。

匿名管道是最簡單的父子進程通訊機制,掌握句柄繼承與標準 I/O 重導向,即可快速實現進程間資料傳遞。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved