CreatePipe匿名管道通信
生活随笔
收集整理的這篇文章主要介紹了
CreatePipe匿名管道通信
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
管道(Pipe)實際是用于進程間通信的一段共享內(nèi)存,創(chuàng)建管道的進程稱為管道服務(wù)器,連接到一個管道的進程為管道客戶機。一個進程在向管道寫入數(shù)據(jù)后,另一進程就可以從管道的另一端將其讀取出來。匿名管道(Anonymous Pipes)是在父進程和子進程間單向傳輸數(shù)據(jù)的一種未命名的管道,只能在本地計算機中使用,而不可用于網(wǎng)絡(luò)間的通信。
匿名管道實施細則
匿名管道由CreatePipe()函數(shù)創(chuàng)建,該函數(shù)在創(chuàng)建匿名管道的同時返回兩個句柄:管道讀句柄和管道寫句柄。CreatePipe()的函數(shù)原型為:
BOOL CreatePipe(PHANDLE hReadPipe, // 指向讀句柄的指針
PHANDLE hWritePipe, // 指向?qū)懢浔闹羔?br /> LPSECURITY_ATTRIBUTES lpPipeAttributes, // 指向安全屬性的指針
DWORD nSize // 管道大小
);?
通過hReadPipe和hWritePipe所指向的句柄可分別以只讀、只寫的方式去訪問管道。在使用匿名管道通信時,服務(wù)器進程必須將其中的一個句柄傳送給客戶機進程。句柄的傳遞多通過繼承來完成,服務(wù)器進程也允許這些句柄為子進程所繼承。除此之外,進程也可以通過諸如DDE或共享內(nèi)存等形式的進程間通信將句柄發(fā)送給與其不相關(guān)聯(lián)的進程。?
在調(diào)用CreatePipe()函數(shù)時,如果管道服務(wù)器將lpPipeAttributes 指向的SECURITY_ATTRIBUTES數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)成員bInheritHandle設(shè)置為TRUE,那么CreatePipe()創(chuàng)建的管道讀、寫句柄將會被繼承。管道服務(wù)器可調(diào)用DuplicateHandle()函數(shù)改變管道句柄的繼承。管道服務(wù)器可以為一個可繼承的管道句柄創(chuàng)建一個不可繼承的副本或是為一個不可繼承的管道句柄創(chuàng)建一個可繼承的副本。CreateProcess()函數(shù)還可以使管道服務(wù)器有能力決定子進程對其可繼承句柄是全部繼承還是不繼承。
在生成子進程之前,父進程首先調(diào)用Win32 API SetStdHandle()使子進程、父進程可共用標準輸入、標準輸出和標準錯誤句柄。當父進程向子進程發(fā)送數(shù)據(jù)時,用SetStdHandle()將管道的讀句柄賦予標準輸入句柄;在從子進程接收數(shù)據(jù)時,則用SetStdHandle()將管道的寫句柄賦予標準輸出(或標準錯誤)句柄。然后,父進程可以調(diào)用進程創(chuàng)建函數(shù)CreateProcess()生成子進程。如果父進程要發(fā)送數(shù)據(jù)到子進程,父進程可調(diào)用WriteFile()將數(shù)據(jù)寫入到管道(傳遞管道寫句柄給函數(shù)),子進程則調(diào)用GetStdHandle()取得管道的讀句柄,將該句柄傳入ReadFile()后從管道讀取數(shù)據(jù)。
如果是父進程從子進程讀取數(shù)據(jù),那么由子進程調(diào)用GetStdHandle()取得管道的寫入句柄,并調(diào)用WriteFile()將數(shù)據(jù)寫入到管道。然后,父進程調(diào)用ReadFile()從管道讀取出數(shù)據(jù)(傳遞管道讀句柄給函數(shù))。
在用WriteFile()函數(shù)向管道寫入數(shù)據(jù)時,只有在向管道寫完指定字節(jié)的數(shù)據(jù)后或是在有錯誤發(fā)生時函數(shù)才會返回。如管道緩沖已滿而數(shù)據(jù)還沒有寫完,WriteFile()將要等到另一進程對管道中數(shù)據(jù)讀取以釋放出更多可用空間后才能夠返回。管道服務(wù)器在調(diào)用CreatePipe()創(chuàng)建管道時以參數(shù)nSize對管道的緩沖大小作了設(shè)定。
匿名管道并不支持異步讀、寫操作,這也就意味著不能在匿名管道中使用ReadFileEx()和WriteFileEx(),而且ReadFile()和WriteFile()中的lpOverLapped參數(shù)也將被忽略。匿名管道將在讀、寫句柄都被關(guān)閉后退出,也可以在進程中調(diào)用CloseHandle()函數(shù)來關(guān)閉此句柄
/
匿名管道程序示例
總的來說,匿名管道程序是比較簡單的。在下面將要給出的程序示例中,將由父進程(管道服務(wù)器)創(chuàng)建一個子進程(管道客戶機),子進程回見個其全部的標準輸出發(fā)送到匿名管道中,父進程再從管道讀取數(shù)據(jù),一直到子進程關(guān)閉管道的寫句柄。其中,匿名管道服務(wù)器程序的實現(xiàn)清單如下:
STARTUPINFO si;
PROCESS_INFORMATION pi;
char ReadBuf[100];
DWORD ReadNum;
HANDLE hRead; // 管道讀句柄
HANDLE hWrite; // 管道寫句柄
BOOL bRet = CreatePipe(&hRead, &hWrite, NULL, 0); // 創(chuàng)建匿名管道
if (bRet == TRUE)
printf("成功創(chuàng)建匿名管道!\n");
else
printf("創(chuàng)建匿名管道失敗,錯誤代碼:%d\n", GetLastError());
// 得到本進程的當前標準輸出
HANDLE hTemp = GetStdHandle(STD_OUTPUT_HANDLE);
// 設(shè)置標準輸出到匿名管道
SetStdHandle(STD_OUTPUT_HANDLE, hWrite);
GetStartupInfo(&si); // 獲取本進程的STARTUPINFO結(jié)構(gòu)信息
bRet = CreateProcess(NULL, "Client.exe", NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi); // 創(chuàng)建子進程
SetStdHandle(STD_OUTPUT_HANDLE, hTemp); // 恢復(fù)本進程的標準輸出
if (bRet == TRUE) // 輸入信息
printf("成功創(chuàng)建子進程!\n");
else
printf("創(chuàng)建子進程失敗,錯誤代碼:%d\n", GetLastError());
CloseHandle(hWrite); // 關(guān)閉寫句柄
// 讀管道直至管道關(guān)閉
while (ReadFile(hRead, ReadBuf, 100, &ReadNum, NULL))
{
ReadBuf[ReadNum] = '\0';
printf("從管道[%s]讀取%d字節(jié)數(shù)據(jù)\n", ReadBuf, ReadNum);
}
if (GetLastError() == ERROR_BROKEN_PIPE) // 輸出信息
printf("管道被子進程關(guān)閉\n");
else
printf("讀數(shù)據(jù)錯誤,錯誤代碼:%d\n", GetLastError());?
在本示例中,將當前進程的標準輸出設(shè)置為使用匿名管道,再創(chuàng)建子進程,子進程將繼承父進程的標準輸出,然后再將父進程的標準輸出恢復(fù)為其初始狀態(tài)。于是父進程便可從管道讀取數(shù)據(jù),直到有錯誤發(fā)生或關(guān)閉管道寫入端的所有句柄。創(chuàng)建的子進程只是向標準輸出和標準錯誤發(fā)送一些文本信息,其中發(fā)送給標準輸出的文本將重定向輸出到管道,發(fā)送給標準錯誤的文本將不改變輸出。下面給出子進程的實現(xiàn)代碼:
int main(int argc, char* argv[])
{
for (int i = 0; i < 100; i++) // 發(fā)送一些數(shù)據(jù)到標準輸出和標準錯誤
{
printf("i = %d\n", i); // 打印提示
cout << "標準輸出:" << i << endl; // 打印到標準輸出
cerr << "標準錯誤:" << i << endl; // 打印到標準錯誤
}
return 0;
匿名管道實施細則
匿名管道由CreatePipe()函數(shù)創(chuàng)建,該函數(shù)在創(chuàng)建匿名管道的同時返回兩個句柄:管道讀句柄和管道寫句柄。CreatePipe()的函數(shù)原型為:
BOOL CreatePipe(PHANDLE hReadPipe, // 指向讀句柄的指針
PHANDLE hWritePipe, // 指向?qū)懢浔闹羔?br /> LPSECURITY_ATTRIBUTES lpPipeAttributes, // 指向安全屬性的指針
DWORD nSize // 管道大小
);?
通過hReadPipe和hWritePipe所指向的句柄可分別以只讀、只寫的方式去訪問管道。在使用匿名管道通信時,服務(wù)器進程必須將其中的一個句柄傳送給客戶機進程。句柄的傳遞多通過繼承來完成,服務(wù)器進程也允許這些句柄為子進程所繼承。除此之外,進程也可以通過諸如DDE或共享內(nèi)存等形式的進程間通信將句柄發(fā)送給與其不相關(guān)聯(lián)的進程。?
在調(diào)用CreatePipe()函數(shù)時,如果管道服務(wù)器將lpPipeAttributes 指向的SECURITY_ATTRIBUTES數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)成員bInheritHandle設(shè)置為TRUE,那么CreatePipe()創(chuàng)建的管道讀、寫句柄將會被繼承。管道服務(wù)器可調(diào)用DuplicateHandle()函數(shù)改變管道句柄的繼承。管道服務(wù)器可以為一個可繼承的管道句柄創(chuàng)建一個不可繼承的副本或是為一個不可繼承的管道句柄創(chuàng)建一個可繼承的副本。CreateProcess()函數(shù)還可以使管道服務(wù)器有能力決定子進程對其可繼承句柄是全部繼承還是不繼承。
在生成子進程之前,父進程首先調(diào)用Win32 API SetStdHandle()使子進程、父進程可共用標準輸入、標準輸出和標準錯誤句柄。當父進程向子進程發(fā)送數(shù)據(jù)時,用SetStdHandle()將管道的讀句柄賦予標準輸入句柄;在從子進程接收數(shù)據(jù)時,則用SetStdHandle()將管道的寫句柄賦予標準輸出(或標準錯誤)句柄。然后,父進程可以調(diào)用進程創(chuàng)建函數(shù)CreateProcess()生成子進程。如果父進程要發(fā)送數(shù)據(jù)到子進程,父進程可調(diào)用WriteFile()將數(shù)據(jù)寫入到管道(傳遞管道寫句柄給函數(shù)),子進程則調(diào)用GetStdHandle()取得管道的讀句柄,將該句柄傳入ReadFile()后從管道讀取數(shù)據(jù)。
如果是父進程從子進程讀取數(shù)據(jù),那么由子進程調(diào)用GetStdHandle()取得管道的寫入句柄,并調(diào)用WriteFile()將數(shù)據(jù)寫入到管道。然后,父進程調(diào)用ReadFile()從管道讀取出數(shù)據(jù)(傳遞管道讀句柄給函數(shù))。
在用WriteFile()函數(shù)向管道寫入數(shù)據(jù)時,只有在向管道寫完指定字節(jié)的數(shù)據(jù)后或是在有錯誤發(fā)生時函數(shù)才會返回。如管道緩沖已滿而數(shù)據(jù)還沒有寫完,WriteFile()將要等到另一進程對管道中數(shù)據(jù)讀取以釋放出更多可用空間后才能夠返回。管道服務(wù)器在調(diào)用CreatePipe()創(chuàng)建管道時以參數(shù)nSize對管道的緩沖大小作了設(shè)定。
匿名管道并不支持異步讀、寫操作,這也就意味著不能在匿名管道中使用ReadFileEx()和WriteFileEx(),而且ReadFile()和WriteFile()中的lpOverLapped參數(shù)也將被忽略。匿名管道將在讀、寫句柄都被關(guān)閉后退出,也可以在進程中調(diào)用CloseHandle()函數(shù)來關(guān)閉此句柄
/
匿名管道程序示例
總的來說,匿名管道程序是比較簡單的。在下面將要給出的程序示例中,將由父進程(管道服務(wù)器)創(chuàng)建一個子進程(管道客戶機),子進程回見個其全部的標準輸出發(fā)送到匿名管道中,父進程再從管道讀取數(shù)據(jù),一直到子進程關(guān)閉管道的寫句柄。其中,匿名管道服務(wù)器程序的實現(xiàn)清單如下:
STARTUPINFO si;
PROCESS_INFORMATION pi;
char ReadBuf[100];
DWORD ReadNum;
HANDLE hRead; // 管道讀句柄
HANDLE hWrite; // 管道寫句柄
BOOL bRet = CreatePipe(&hRead, &hWrite, NULL, 0); // 創(chuàng)建匿名管道
if (bRet == TRUE)
printf("成功創(chuàng)建匿名管道!\n");
else
printf("創(chuàng)建匿名管道失敗,錯誤代碼:%d\n", GetLastError());
// 得到本進程的當前標準輸出
HANDLE hTemp = GetStdHandle(STD_OUTPUT_HANDLE);
// 設(shè)置標準輸出到匿名管道
SetStdHandle(STD_OUTPUT_HANDLE, hWrite);
GetStartupInfo(&si); // 獲取本進程的STARTUPINFO結(jié)構(gòu)信息
bRet = CreateProcess(NULL, "Client.exe", NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi); // 創(chuàng)建子進程
SetStdHandle(STD_OUTPUT_HANDLE, hTemp); // 恢復(fù)本進程的標準輸出
if (bRet == TRUE) // 輸入信息
printf("成功創(chuàng)建子進程!\n");
else
printf("創(chuàng)建子進程失敗,錯誤代碼:%d\n", GetLastError());
CloseHandle(hWrite); // 關(guān)閉寫句柄
// 讀管道直至管道關(guān)閉
while (ReadFile(hRead, ReadBuf, 100, &ReadNum, NULL))
{
ReadBuf[ReadNum] = '\0';
printf("從管道[%s]讀取%d字節(jié)數(shù)據(jù)\n", ReadBuf, ReadNum);
}
if (GetLastError() == ERROR_BROKEN_PIPE) // 輸出信息
printf("管道被子進程關(guān)閉\n");
else
printf("讀數(shù)據(jù)錯誤,錯誤代碼:%d\n", GetLastError());?
在本示例中,將當前進程的標準輸出設(shè)置為使用匿名管道,再創(chuàng)建子進程,子進程將繼承父進程的標準輸出,然后再將父進程的標準輸出恢復(fù)為其初始狀態(tài)。于是父進程便可從管道讀取數(shù)據(jù),直到有錯誤發(fā)生或關(guān)閉管道寫入端的所有句柄。創(chuàng)建的子進程只是向標準輸出和標準錯誤發(fā)送一些文本信息,其中發(fā)送給標準輸出的文本將重定向輸出到管道,發(fā)送給標準錯誤的文本將不改變輸出。下面給出子進程的實現(xiàn)代碼:
int main(int argc, char* argv[])
{
for (int i = 0; i < 100; i++) // 發(fā)送一些數(shù)據(jù)到標準輸出和標準錯誤
{
printf("i = %d\n", i); // 打印提示
cout << "標準輸出:" << i << endl; // 打印到標準輸出
cerr << "標準錯誤:" << i << endl; // 打印到標準錯誤
}
return 0;
}?
總結(jié)
以上是生活随笔為你收集整理的CreatePipe匿名管道通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。