管道包括三種:
1):普通管道PIPE,通常有很多限制,一是半雙工,只能單向傳輸,二是只能在父子進程間使用
2):流管道:這種能雙向傳輸,但是也是只能父子進程間使用。
3):命名管道,去除了以上的第二種限制,可以在許多不相關的進程間進行通訊。也是半雙工的通信方式。
通常我們把管道分為匿名管道和命名管道。但對於匿名管道的話,只能在本機上進程之間通信,而且只能實現本地的父子進程之間的通信,局限性太大了。命名管道,就和匿名管道有些不同了,在功能上也就顯得強大許多,至少其可以實現跨網絡之間的進程的通信,同時其客戶端既可以接收數據也可以發送數據,服務器端也是可以接收數據,又可以發送數據。
匿名管道的概述
對於匿名管道而言,命名管道使用了windows安全機制,因而命名管道的服務器端可以控制哪些客戶有權與其建立連接。哪些客戶端是不能夠與這個命名管道建立連接的。命名管道的通信是以連接的方式進行的,服務器創建一個命名管道對象,然后在此對象上等待連接請求,一旦客戶連接過來,則兩者都可以通過命名管道讀或者寫數據。
命名管道提供了兩種通信模式:字節模式和消息模式。在字節模式下,數據以一個連續的字節流的形式在客戶機和服務器之間流動。而在消息模式下,客戶機和服務器則通過一系列不連續的數據單位,進行數據的收發,每次在管道上發出一個消息后,它必須作為一個完整的消息讀入。
命名管道的使用步驟
服務器端:
1):服務器進程調用CreateNamedPipe函數來創建一個有名稱的命名管道在創建命名管道的時候必須指定一個本地的命名管道名稱。windows允許同一個本地的命名管道名稱右多個命名管道實例。所以,服務器進程在調用CreateNamedPipe函數時必須指定最大允許的實例數(0-255).如果CreateNamedPipe函數成功返回后,服務器進程得到一個指向一個命名管道實例的句柄。
2):服務器進程就可以調用ConnectNamedPipe來等待客戶的連接請求,這個ConnectNamedPipe既支持同步形式,又支持異步形式,若服務器進程以同步形式調用 ConnectNamedPipe函數,如果沒有得到客戶端的連接請求,則會一直等到客戶端的連接請求。當該函數返回時,客戶端和服務器之間的命名管道連接已經建立起來了。
3):這個時候服務器端就可以向客戶端讀(ReadFile)/寫(WriteFile)數據了。
4):在已經建立連接的命名管道實例中,服務器進程就會得到一個指向該管道實例的句柄,這個句柄稱之為服務器端句柄,同時服務端進程可以調用DisconnectNamedPipe函數,將一個管道實例與當前建立連接的客戶端進程斷開,從而可以重新連接到新的客戶端進程。當然,服務器也可以調用CloseHandle來關閉一個已經建立連接的命名管道實例。
客戶端:
1):客戶端進程調用CreateFile函數連接到一個正在等待連接的命名管道上。在這里客戶端需要指定將要連接的命名管道上。當CreateFile成功返回之后,客戶端就得到了一個指向已經建立連接的命名管道實例的句柄。在這里客戶端也可以先調用WaitNamedPipe函數來測試指定名稱的管道實例是否可用。在已經建立的命名管道實例中,客戶端進程就會得到一個指向該管道實例的句柄。這個句柄稱之為客戶端句柄。
2):這個時候客戶端就可以向服務器讀(ReadFile)/寫(WriteFile)數據了.
3):客戶端可以調用CloseHandle來關閉一個已經建立連接的命名管道實例。
CreateNamedPipe:
1 //創建命名管道的函數的使用
2 CreateNamedPipe("\\\\.\\Pipe\\Test",PIPE_ACCESS_DUPLEX,PIPE_NOWAIT,10,1024,1024,100,NULL) 3 1、為創建的管道命名 4 2、指定管道的訪問方式、重疊方式、寫直通方式以及管道句柄的安全訪問方式(PIPE_ACCESS_DUPLEX這里指雙向模式) 5 3、指定管道句柄的類型、讀取和等待方式(PIPE_NOWAIT指允許非阻塞方式) 6 4、指定管道能夠創建的實例的最大數目 7 5、指定為輸出緩沖區所保留的字節數 8 6、指定為輸入緩沖區所保留的字節數 9 7、指定默認超時時間,單位ms,同一管道的不同實例指定值需要相同 10 8、指向SECURITY_ATTRIBUTES結構的指針,該結構指定了命名管道的安全描述符
該函數用來創建一個命名管道的實例,並返回這個命名管道的句柄。如果需要創建一個命名管道的多個實例,就需要多次調用CreateNamedPipe函數,參數 lpName 為一個字符串,其格式必須為 \\.\pipe\pipeName,其中圓點 ”.” 表示的是本地機器,如果想要與遠程的服務器建立連接,那么這個圓點位置處應指定這個遠程服務器的名稱,而其中的 “pipe” 這個是個固定的字符串,也就是說不能進行改變的,最后的 “pipename” 則代表的是我將要創建的命名管道的名稱了,參數 dwOpenMode 用來指定管道的訪問方式,重疊方式,寫直通方式,還有管道句柄的安全訪問方式。
ConnectNamedPipe:
1 //服務器等待客戶端的連接請求的到來(並非連接服務器端的命名管道!)
2 ConnectNamedPipe(hPipe, NULL) 3 1、指向一個命名管道實例的服務器的句柄,該句柄由CreateNamedPipe函數返回 4 2、指向OVERLAPPED結構體的指針,默認為NULL,表明使用默認的同步IO方式
接收客戶端發送數據ReadFile & 向客戶端發送數據WriteFile:
1 //文件的寫入
2 WriteFile(hPipe, strMessage, sizeof(strMessage), &wLen, 0) 3
4 1、指定要寫入數據的文件的句柄 5 2、指向包含將要將要寫入文件的數據的緩沖區的指針 6 3、指明要向文件中寫入的字節數 7 4、用來接收實際寫入到文件中的字節數 8 5、指向OVERLAPPED結構體的指針,默認為NULL,表明使用默認的同步IO方式
//文件的讀取
1 ReadFile(hPipe, buf, 256, &rLen, NULL) 2 1、指定要讀取數據的文件的句柄 3 2、指向包含將要將要接收的文件中讀取數據的緩沖區的指針 4 3、指明要向文件中讀取的字節數 5 4、用來接收實際讀取到的字節數 6 5、指向OVERLAPPED結構體的指針,默認為NULL,表明使用默認的同步IO方式
CloseHandle:
CloseHandle(hPipe); //關閉管道句柄
客戶端單獨用到的兩個函數
WaitNamedPipe:
1 WaitNamedPipe(TEXT("\\\\.\\Pipe\\pipeTest"), NMPWAIT_WAIT_FOREVER) 2 1、指定命名管道的名稱 3 2、指定超時間隔,NMPWAIT_WAIT_FOREVER表示一直等待,直到出現了一個可用的命名管道的實例
CreateFile:
CreateFile("\\\\.\\Pipe\\Test",GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); 1、指定用於創建或打開的對象的名稱 2、指定對象的訪問方式,GENERIC_WRITE表示指定對象具有寫訪問 3、指定共享方式,如果此參數為0,表示對象不能被共享 4、指向SECURITY_ATTRIBUTES結構的指針,該結構指定了命名管道的安全描述符,如果沒有特殊的需求,默認值為NULL 5、指定如何創建文件(OPEN_EXISTING表示打開文件,如果文件不存在,則函數調用失敗) 6、設置文件屬性和標志(FILE_ATTRIBUTE_NORMAL表示該文件沒有其他屬性設置) 7、指定具有GENERIC_READ訪問方式的模板文件的句柄