一.基本的理論知識
1.什麼是管道以及分類 管道是兩個頭的東西,每個頭各連接一個進程或者同一個進程的不同代碼,按照管道的類別分有兩種管道,匿名的和命名的;按照管道的傳輸方向分也可以分成兩種,單向的雙向的。根據管道的特點,命名管道通常用在網絡環境下不同計算機上運行的進程之間的通信(當然也可以用在同一台機的不同進程中)它可以是單向或雙向的;而匿名管道只能用在同一台計算機中,它只能是單向的。匿名管道其實是通過用給了一個指定名字的有名管道來實現的。
使用管道的好處在於:讀寫它使用的是對文件操作的 api,結果操作管道就和操作文件一樣。即使你在不同的計算機之間用命名管道來通信,你也不必了解和自己去實現網絡間通信的具體細節。
2.管道的使用 A.命名管道 命名管道是由服務器端的進程建立的,管道的命名必須遵循特定的命名方法,就是
"\\.\pipe\管道名",當作為客戶端的進程要使用時,使用
"\\計算機名\\pipe\管道名"來打開使用,具體步驟如下:
服務端通過函數
CreateNamedPipe
IZE: 7.5pt; COLOR: #4b4b4b">創建一個命名管道的實例並返回用於今後操作的句柄,或為已存在的管道創建新的實例。服務端偵聽來自客戶端的連接請求,該功能通過ConnectNamedPipe函數實現。
客戶端通過函數WaitNamedPipe來等待管道的出現,如果在超時值變為零以前,有一個管道可以使用,則 WaitNamedPipe將返回 True,並通過調用CreateFile或CallNamedPipe來呼叫對服務端的連接。
此時服務端將接受客戶端的連接請求,成功建立連接,服務端ConnectNamedPipe返回 True 建立連接之後,客戶端與服務器端即可通過ReadFile和WriteFile,利用得到的管道文件句柄,彼此間進行信息交換。當客戶端與服務端的通信結束,客戶端調用CloseFile,服務端接著調用DisconnectNamedPipe。最後調用函數CloseHandle來關閉該管道。
B
>.匿名管道
由於命名管道使用時作為客戶端的程序必須知道管道的名稱,所以更多的用在同一“作者”編寫的服務器/工作站程序中,你不可能隨便找出一個程序來要求它和你寫的程序來通過命名管道通信。而匿名管道的使用則完全不同,它允許你和完全不相干的進程通信,條件是這個進程通過控制台“console”來輸入輸出,典型的例子是老的 DOS 應用程序,它們在運行時 Windows 為它們開了個 DOS 窗口,它們的輸入輸出就是 console 方式的。還有一些標准的 Win32 程序也使用控制台輸入輸出,如果在 Win32 編程中不想使用圖形界面,你照樣可以使用AllocConsole得到一個控制台,然後通過GetStdHandle得到輸入或輸出句柄,再通過WriteConsole或 WriteFile 把結果輸出到控制台(通常是一個象 Dos 窗口)的屏幕上。雖然這些程序看起來象 DOS 程序,
但它們是不折不扣的 Win32 程序,如果你在純 DOS 下使用,就會顯示“The program must run under Windows!”。
一個控制台有三個句柄:標准輸入、標准輸出和和標准錯誤句柄,標准輸入、標准輸出句柄是可以重新定向的,你可以用匿名管道來代替它,這樣一來,你可以在管道的另一端用別的進程來接收或輸入,而控制台一方並沒有感到什麼不同,就象 DOS 下的 > 或者 < 可以重新定向輸出或輸入一樣。通常控制台程序的輸入輸出如下:
(控制台進程output) write ----> 標准輸出設備(一般是屏幕)
(控制台進程input) read <---- 標准輸入設備(一般是鍵盤)
而用管道代替後: (作為子進程的控制台進程output) write ----> 管道1 ----> read (父進程)
(作為子進程的控制台進程
: 7.5pt; COLOR: #4b4b4b">input) read <----> 管道2 <---- write (父進程)
使用匿名管道的步驟如下:
使用
CreatePipe建立兩個管道,得到管道句柄,一個用來輸入,一個用來輸出
准備執行控制台子進程,首先使用
GetStartupInfo得到
StartupInfo 使用第一個管道句柄代替 StartupInfo 中的 hStdInput,第二個代替 hStdOutput、hStdError,即標准輸入、輸出、錯誤句柄
使用
CreateProcess執行子進程,這樣建立的子進程輸入和輸出就被定向到管道中
父進程通過 ReadFile 讀第二個管道來獲得子進程的輸出,通過 WriteFile 寫第一個管道來將輸入寫到子進程
父進程可以通過
PeekNamedPipe
.5pt; COLOR: #4b4b4b">來查詢子進程有沒有輸出
子進程結束後,要通過
CloseHandle來關閉兩個管道。
二.管道使用的API函數集
CallNamedPipe函數
函數原型:BOOL CallNamedPipe( LPCTSTR lpNamedPipeName,
LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWord nTimeOut );
說明:這個函數由一個希望通過管道通信的一個客戶進程調用。如有可能,它就同一個管道連接(在必要的情況下等候管道可用)。隨後,它對指定的數據進行讀寫,然後將管道關閉
返回值 : Long,非零表示成功,零表示失敗。會設置GetLastError
參數表 :
lpNamedPipeName: LPCTSTR,指定管道名,采用的形式是:\\.\管道\管道名。
最多可達256個字符的長度,而且不用區分大小寫。如果存在指定名字的一個管道,則創建那個管道的一個新實例
lpInBuffer: LPVOID,包含了要寫入管道的數據的一個內存緩沖區
nInBufferSize:DWord,lpInBuffer緩沖區中的字符數量
lpOutBuffer:LPVOID,指定一個內存緩沖區,用於裝載從管道中讀出的數據
nOutBufferSize:DWord,指定一個長整數變量,用於裝載來自管道的數據
lpBytesRead:LPDWord,指定從管道中讀出的字節數。會閱讀單條消息。如lpOutBuffer的容量不夠大,不能容下整條消息,則函數會返回FALSE,而且GetLastError會設為ERROR_MORE_DATA(消息中留下的任何字節都會丟失)
nTimeOut:DWord,下列常量之一:
1.
FONT-SIZE: 7.5pt">NMPWAIT_NOWAIT: 如管道不可用,則立即返回一個錯誤
2.
NMPWAIT_WAIT_FOREVER:永遠等候管道可用.
3. NMPWAIT_USE_DEFAULT_WAIT:使用管道的默認超時設置,這個設置是用CreateNamedPipe函數指定的
ConnectNamedPipe 函數
ING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 384.45pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="513">
函數原型:BOOL ConnectNamedPipe( HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped );
說明:指示一台服務器等待下去,直至客戶機同一個命名管道連接
返回值:BOOL,如lpOverlapped為NULL,那麼:
1. 如管道已連接,就返回Ture(非零);如發生錯誤,或者管道已經連接,就返回零(GetLastError此時會返回ERROR_PIPE_CONNECTED)
2. lpOverlapped有效,就返回零;如管道已經連接,GetLastError會返回ERROR_PIPE_CONNECTED;如重疊操作成功完成,就返回ERROR_IO_PENDING。在這兩種情況下,倘若一個客戶已關閉了管道,且服務器尚未用DisconnectNamedPipe函數同客戶斷開連接,那麼GetLastError都會返回ERROR_NO_DATA
參數: hNamedPipe:HANDLE,管道的句柄
lpOverlapped:LPOVERLAPPED,如設為NULL(傳遞文章整理:
>ByVal As Long),表示將線程掛起,直到一個客戶同管道連接為止。否則就立即返回;此時,如管道尚未連接,客戶同管道連接時就會觸發lpOverlapped結構中的事件對象。隨後,可用一個等待函數來監視連接
適用平台:Windows NT
注釋:可用這個函數將一個管道換成同另一個客戶連接,但首先必須用DisconnectNamedPipe函數斷開同當前進程的連接
DING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 384.45pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="513">
CreateNamedPipe 函數 函數原型:HANDLE CreateNamedPipe( LPCTSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWord nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
說明:創建一個命名管道。返回的句柄由管道的服務器端使用
返回值:HANDLE,如執行成功,返回管道的句柄。INVALID_HANDLE_VALUE表示失敗文章整理:
e="FONT-SIZE: 7.5pt">.會設置GetLastError
參數: lpName:LPCTSTR,指定管道名,采用的形式是:
\\.\管道\管道名。最多可達256個字符的長度,而且不用區分大小寫。如果存在指定名字的一個管道,則創建那個管道的一個新實例
dwOpenMode:DWord,下述常數組的一個組合
下述常數之一(對於管道的所有實例都要一樣):
1.
PIPE_Access_DUPLEX管道是雙向的
2.
PIPE_Access_INBOUND數據從客戶端流到服務器端
E: 7.5pt">3.
PIPE_Access_OUTBOUND數據從服務器端流到客戶端
下述常數的任意組合
1.
FILE_FLAG_WRITE_THROUGH在網絡中建立的字節型管道內,強迫數據在每次讀寫操作的時候通過網絡傳輸。否則傳輸就可能延遲
2. FILE_FLAG_OVERLAPPED 允許(但不要求)用這個管道進行異步(重疊式)操作
常數WRITE_DAC, WRITE_OWNER 和 Access_ SYSTEM_SECURITY提供了附加的安全選項
dwPipeMode:DWord,下述常數組的一個組合
下述常數之一(管道的所有實例都必須指定相同的常數)
1.
PIPE_TYPE_BYTE數據作為一個連續的字節數據流寫入管道
2.
PIPE_TYPE_MESSAGE數據用數據塊(名為“消息
e="FONT-SIZE: 7.5pt">”或“報文”)的形式寫入管道
下述常數之一:
1.
PIPE_READMODE_PIPE數據以單獨字節的形式從管道中讀出
2.
PIPE_READMODE_MESSAGE數據以名為“消息”的數據塊形式從管道中讀出(要求指定PIPE_TYPE_MESSAGE)
下述常數之一:
1.
PIPE_WAIT同步操作在等待的時候掛起線程
2. PIPE_NOWAIT(不推薦!)同步操作立即返回。這樣可為異步傳輸提供一種落後的實現方法,已由Win32的重疊式傳輸機制取代了
nMaxInstances:DWord,這個管道能夠創建的最大實例數量。必須是1
"FONT-SIZE: 7.5pt">到常數PIPE_UNLIMITED_INSTANCES間的一個值。它對於管道的所有實例來說都應是相同的
nOutBufferSize:DWord,建議的輸出緩沖區長度;零表示用默認設置
nInBufferSize:DWord,建議的輸入緩沖區長度;零表示用默認設置
nDefaultTimeOut:DWord,管道的默認等待超時。對一個管道的所有實例來說都應相同
lpSecurityAttributes:LPSECURITY_ATTRIBUTES,指定一個SECURITY_ATTRIBUTES結構,或者傳遞零值(將參數聲明為ByVal As Long,並傳遞零值),以便使用不允許繼承的一個默認描述符
適用平台:Windows NT
T: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" border="1">
CreatePipe 函數 函數原型:BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWord nSize );
說明:創建一個匿名管道
返回值:Long
n>,非零表示成功,零表示失敗。會設置GetLastError
參數:
phReadPipe:PHANDLE,指定一個變量,設為管道讀入(輸出)端的一個句柄
phWritePipe:PHANDLE,指定一個變量,設為管道寫入(輸入)端的一個句柄
lpPipeAttributes:LPSECURITY _ATTRIBUTES,指定一個SECURITY_ATTRIBUTES結構,或者傳遞零值,以便使用不允許繼承的一個默認描述符
nSize:DWord,管道緩沖區的建議大小。零表示用默認值
注解:匿名管道不允許異步操作,所以如在一個管道中寫入數據,且緩沖區已滿,
那麼除非另一個進程從管道中讀出數據,從而騰出了緩沖區的空間,否則寫入函數不會返回
DisconnectNamedPipe 函數
函數原型:BOOL DisconnectNamedPipe( HANDLE hNamedPipe );
說明:斷開一個客戶與一個命名管道的連接
返回值:BOOL,非零表示成功,零表示失敗。會設置GetLastError
參數:hNamedPipe Long,管道的句柄
適用平台:Windows NT
注解:如客戶尚未在它自己那端關閉管道句柄,下次試圖訪問管道的時候就會發生錯誤 <文章整理:學網 http://www.xue5.com (本站) [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] [36] [37]
/td>
GetNamedPipeHandleState 函數
函數原型:BOOL GetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPTSTR lpUserName, DWord nMaxUserNameSize);
說明: 獲取一個命名管道當前的狀態信息歡迎光臨
span>
返回值: BOOL,非零表示成功,零表示失敗。會設置GetLastError
參數:
hNamedPipe Long,指定一個命名管道的句柄
lpState Long,用於裝載下述一個或多個常數的長整數變量 PIPE_NOWAIT 管道設置成永不堵塞,這種模式很少使用 PIPE_READMODE_MESSAGE 管道設置成讀取消息
lpCurInstances Long,裝載這個管道目前存在的實例數量
lpMaxCollectionCount Long,如管道設置成通過一個網絡傳輸數據,就用這個變量裝載通過管道發送之前可排隊等候的最大數據量
lpCollectDataTimeout Long,如管道設置成通過一個網絡傳輸數據,就在這裡指定一個長整數變量,用它裝載進行一次網絡數據傳輸前需要等候的最長時間
lpUserName String,如這是個服務器句柄,就在這裡指定一個字串緩沖區,在其中載入客戶應用程序的用戶名。可設為vbNullString,表示不取回信息
nMaxUserNameSize Long,指定lpUserName緩沖區的長度,可以為零
GetNamedPipeInfo 函數
函數原型:BOOL GetNamedPipeInfo(HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutBufferSize, LPDWORD lpInBufferSize, LPDWord lpMaxInstances);
說明:獲得指定命名管道的信息
返回值:如果函數執行成功,返回值非零,否則,返回值為零,此時調用GetLastError函數獲得擴展錯誤信息
參數:
hNamedPipe:命名管道句柄。這個句柄具有命名管道的GENERIC_READ訪問權限。
lpFlags>:指定一個識別命名管道類型的32位變量。如果這個信息不需獲得,可以給此參數置NULL。否則使用以下的值:
1. PIPE_CLIENT_END 這個句柄是關於一個命名管道的客戶端,此值被默認
2. PIPE_SERVER_END 這個句柄是關於命名管道的服務器端。如果這個值沒有被指定,這個命名管道句柄是關於客戶端的
3. PIPE_TYPE_BYTE 命名管道是一個字節管道型,此值被默認
4. PIPE_TYPE_MESSAGE 命名管道是一個消息管道。如果這個值沒有被指定,則默認為字節管道型
lpOutBufferSize:一個32變量地址。用來按字節,返回輸出數據緩沖的尺寸。如果緩沖值為零,則這個緩沖區沒有按要求分配。如果鎮魂歌信息不需要的,可以被置NULL.
lpInBufferSize:一個32變量地址。用來按字節,返回輸入數據緩沖的尺寸。如果緩沖值為零,則這個緩沖區沒有按要求分配。如果這個信息不需要的,可以被置NULL.
lpMaxInstances:一個32變量地址。用來獲得被創建的管道實例的最大尺寸。
如果此位被設置為PIPE_UNLIMITED_INSTANCES,被創建的管道實例的最大尺寸被按照系統的可容量所限制。如果這個信息不需要的,可以被置NULL.
PeekNamedPipe 函數
函數原型: BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer,DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWord lpBytesLeftThisMessage );
DER-LEFT: windowtext 1pt solid; WIDTH: 384.45pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="513">
說明: 預覽一個管道中的數據,或取得與管道中的數據有關的信息
返回值: BOOL,非零表示成功,零表示失敗。會設置GetLastError
參數:
hNamedPipe HANDLE,指定一個管道的句柄。這並不一定是某個命名管道的句柄——匿名管道同樣適用
lpBuffer LPVOID,指定要裝載數據的一個緩沖區的頭一個字符。可以為零
nBufferSize DWord,lpBufferle="FONT-SIZE: 7.5pt">緩沖區長度
lpBytesRead LPDWord,保存裝載到緩沖區的字符數量
lpTotalBytesAvail LPDWord,保存管道中可用的字符數量
lpBytesLeftThisMessage Long,保存這次讀操作後仍然保留在消息中的字符數。只能為那些基於消息的命名管道設置
注解: 由這個函數讀入的數據實際並不能從管道中刪除。如果要對一個管道進行輪詢,了解是否有可能數據,那麼使用這個函數特別理想
#0066cc">SetNamedPipeHandleState 函數
函數原型: BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWord lpCollectDataTimeout );
說明: 設置與一個命名管道的運作有關的信息
返回值值: BOOL,非零表示成功,零表示失敗。會設置GetLastError
GHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 384.45pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="513">
參數:
hNamedPipe HANDLE,指定一個命名管道的句柄
lpMode LPDWord,下列常數的一個或多個:PIPE_WAIT, PIPE_NOWAIT, PIPE_READMODE_BYTE以及 PIPE_READMODE_MESSAGE。請參考CreateNamedPipe函數,了解有關這些標志的進一步情況
pMaxCollectionCount LPDWord,如管道設為通過一個網絡傳輸數據,則在這裡指定通過管道發送之前可排除等候的最大數據量
lpCollectDataTimeout LPDWord,如管道設為通過一個網絡傳輸數據,則在這裡指定網絡數據傳輸前能夠忍受的最長等候時間(超時)
TransactNamedPipe 函數
函數原型: BOOL TransactNamedPipe( HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWord lpBytesRead, LPOVERLAPPED lpOverlapped );
說明: 該函數在單獨一個函數中同時合並了對管道的讀、寫操作。客戶和服務器進程都可用它
pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 384.45pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="513">
返回值: BOOL,如操作已結束,則返回TRUE(非零);否則返回零。在異步模式中,GetLastError會設置成ERROR_IO_PENDING,而且操作會繼續在後台進行。可測試lpOverlapped結構中的事件對象,了解操作是否結束
參數:
hNamedPipe HANDLE,指定一個消息類型的命名管道的句柄
lpInBuffer LPVOID,指定一個內存緩沖區,在其中包含要寫入管道的數據
nInBufferSize DWord,指定lpInBuffer緩沖區中的字節數量
lpOutBuffer LPVOID,指定一個內存緩沖區,用於裝載從管道中讀入的數據
nOutBufferSize DWord,用於裝載來自管道的數據
lpBytesRead LPDWord,指定要從管道讀入的字節數量。會讀入單條消息。如由於lpOutBuffer不夠大,不能容下完整的消息,那麼函數會返回FALSE,而且GetLastError會設為ERROR_MORE_DATA(消息中剩下的所有字節都會丟失)
lpOverlapped LPOVERLAPPED,可以為NULL(變成ByVal As Long,並傳遞零值),或指定包含了一個事件對象的OVERLAPPED結構
注解:如lpOverlapped設為FONT-SIZE: 7.5pt">NULL,或者句柄沒有創建成FILE_FLAG_OVERLAPPED樣式,那麼除非讀和寫操作都完成,否則函數不會返回
WaitNamedPipe 函數 R>函數原型: BOOL WaitNamedPipe(LPCTSTR lpNamedPipeName, DWord nTimeOut ); 文章整理:學網 http://www.xue5.com (本站) [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] [36] [37]
OP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="513">
說明:由一個客戶進程調用,等候一個管道變成可用狀態(比如服務器已調用ConnectNamedPipe函數同一個客戶連接)
返回值:BOOL,非零表示成功;如果失敗,或者管道不存在,則返回零。會設置GetLastError
參數:
lpNamedPipeName LPCTSTR,指定要連接的管道名稱
nTimeOut DWord,以毫秒數表示的等待時間,或者下述常數之一:
1. NMPWAIT_USE_DEFAULT_WAIT使用管道創建時的默認超時設定
2.NT: 7pt 'Times New Roman'"> NMPWAIT_WAIT_FOREVER永遠等待
注解: 在這個函數之後,用CreateFile打開管道。注意從這個函數返回到調用CreateFile函數期間,倘若有另一個進程同管道連接,那麼這個CreateFile調用可能失敗