管道是進程間通訊 (IPC) 的一種共享記憶體機制。建立管道的進程稱為「管道伺服器」,連接管道的進程為「管道客戶端」。資料由一端寫入,另一端讀取,實現單向流動。
匿名管道 特點:
BOOL CreatePipe(
PHANDLE hReadPipe, // 輸出:讀端句柄
PHANDLE hWritePipe, // 輸出:寫端句柄
LPSECURITY_ATTRIBUTES lpPipeAttributes, // 安全屬性(控制繼承性)
DWORD nSize // 緩衝區大小建議值(0 為預設)
);
關鍵點:lpPipeAttributes->bInheritHandle = TRUE 才能讓子進程繼承句柄。
父進程需將管道一端句柄傳給子進程,常用方式:
bInheritHandle = TRUESetStdHandle(STD_OUTPUT_HANDLE, hWrite) 將標準輸出重導向至管道寫端CreateProcess(..., TRUE, ...) 參數 bInheritHandles = TRUEGetStdHandle(STD_INPUT_HANDLE) 取得管道讀端SetStdHandle(STD_OUTPUT_HANDLE, hTemp)#include <windows.h>
#include <stdio.h>
int main() {
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
HANDLE hRead, hWrite;
char buf[1024];
DWORD bytesRead;
// 1. 建立可繼承的匿名管道
SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
printf("建立管道失敗,錯誤碼: %d\n", GetLastError());
return 1;
}
// 2. 設定子進程標準輸出 = 管道寫端
HANDLE hOldOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetStdHandle(STD_OUTPUT_HANDLE, hWrite);
// 3. 啟動子進程
GetStartupInfo(&si);
si.hStdOutput = hWrite;
si.hStdError = hWrite;
si.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, "Child.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
printf("建立子進程失敗: %d\n", GetLastError());
return 1;
}
// 4. 父進程不需要寫端,關閉避免阻塞
CloseHandle(hWrite);
SetStdHandle(STD_OUTPUT_HANDLE, hOldOut); // 恢復父進程標準輸出
// 5. 讀取管道資料直到 EOF
while (ReadFile(hRead, buf, sizeof(buf) - 1, &bytesRead, NULL) && bytesRead > 0) {
buf[bytesRead] = '\0';
printf("[父進程讀取] %s", buf);
}
DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE) printf("管道已由子進程關閉\n");
else if (err != ERROR_SUCCESS) printf("讀取錯誤: %d\n", err);
CloseHandle(hRead);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
#include <windows.h>
#include <stdio.h>
#include <iostream>
int main() {
for (int i = 0; i < 10; ++i) {
printf("stdout: 第 %d 行輸出\n", i); // 導向管道
fprintf(stderr, "stderr: 錯誤訊息 %d\n", i); // 導向管道(因 hStdError = hWrite)
Sleep(100);
}
return 0; // 進程結束自動關閉句柄,父進程 ReadFile 返回 FALSE
}
| 項目 | 說明 |
|---|---|
| 同步阻塞 | WriteFile 在緩衝區滿時阻塞;ReadFile 在無資料時阻塞 |
| 非支援異步 | 匿名管道不支援 ReadFileEx/WriteFileEx,lpOverlapped 會被忽略 |
| 關閉條件 | 所有寫端句柄關閉後,讀端 ReadFile 返回 0(EOF) |
| 緩衝區大小 | 建議值 4KB~64KB,過大浪費記憶體,過小增加切換開銷 |
| 錯誤處理 | 務必檢查 GetLastError(),區分 ERROR_BROKEN_PIPE(正常結束)與其他錯誤 |
DuplicateHandle 跨進程傳遞句柄,或使用命名管道匿名管道雖簡單,但掌握「句柄繼承 + 標準流重導向」的核心模式,是 Windows IPC 開發的必修課。