郵槽和命名管道的區別
阿新 • • 發佈:2019-01-06
郵槽:只允許從客戶端傳送到伺服器,沒有可靠性保證,根據廣播通訊體系所設計,使用郵槽可以建立不可靠的單向資料傳輸。其優點就是可以很方便的向一個或者多個伺服器廣播訊息
管道(Pipe)實際是用於程序間通訊的一段共享記憶體,建立管道的程序稱為管道伺服器,連線到一個管道的程序為管道客戶機。命名管道(Named Pipes)是在管道伺服器和一臺或多臺管道客戶機之間進行單向或雙向通訊的一種命名的管道。一個命名管道的所有例項共享同一個管道名,但是每一個例項均擁有獨立的快取與控制代碼,並且為客戶——服務通訊提供有一個分離的管道。例項的使用保證了多個管道客戶能夠在同一時間使用同一個命名管道。
訊息管道(Message Pipe)
用於設定應用程式間的一條永久通訊通道,通過該通道可以象自己的應用程式訪問一個平面檔案一樣讀寫資料。
匿名管道 (Anonymous Pipes)
單向流動,並且只能夠在同一電腦上的各個程序之間流動。
命名管道(Named Pipes)
雙向,跨網路,任何程序都可以輕易的抓住,放進管道的資料有固定的格式,而使用ReadFile()只能讀取該大小的倍數。
可以被使用於I/O Completion Ports
相同點:
1、 都是程序間的通訊
2、 都是在重新命名機制的基礎上實現的()
3、 都採用通用命名規則UNC(Universal Naming Convention)
4、 支援多客戶端連結???
不同點:
1、 郵槽是單向通訊,伺服器只讀,客戶端只寫,不支援重疊IO模式
2、 命名管道,可以是雙向通訊,可以採用重疊IO模式
郵槽的實現 :
服務端:
1) 用CreateMailslot API函式建立一個郵槽控制代碼。
2) 呼叫ReadFile API函式,並使用現成的郵槽控制代碼,從任何客戶機接收資料。
客戶端:
1) 使用CreateFile這個API函式,針對想向其傳送資料的郵槽,開啟指向它的一個引用句
柄。 2) 呼叫WriteFile這個API函式,向郵槽寫入資料。 命名管道的實現: 服務端: 1) 使用API函式CreateNamedPipe,建立一個命名管道例項控制代碼。
2) 使用API函式ConnectNamedPipe,在命名管道例項上監聽客戶機連線請求。
3) 分別使用ReadFile和WriteFile這兩個API函式,從客戶機接收資料,或將資料發給客戶
機。
4) 使用API函式DisconnectNamedPipe,關閉命名管道連線。
5) 使用API函式CloseHandle,關閉命名管道例項控制代碼。 客戶端: 1) 用API函式WaitNamedPipe,等候一個命名管道例項可供自己使用。
2) 用API函式CreateFile,建立與命名管道的連線。
3) 用API函式WriteFile和ReadFile,分別向伺服器傳送資料,或從中接收資料。
4) 用API函式CloseHandle,關閉開啟的命名管道會話。 命名管道的程式碼實現: 服務端: view plaincopy to clipboardprint? // PipeServer.cpp : Defines the entry point for the console application. // 管道通訊伺服器 #include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <iostream> using namespace std; #define NUM_PIPES 5 #define BUFFER_SIZE 256 int _tmain(int argc, _TCHAR* argv[]) { DWORD dwTransferred; HANDLE hPipe[NUM_PIPES]; char szBuffer[NUM_PIPES][BUFFER_SIZE]; OVERLAPPED Ovlap[NUM_PIPES]; HANDLE hEvent[NUM_PIPES]; DWORD dwTime = 1000; BOOL bRead[NUM_PIPES]; for ( int i = 0; i < NUM_PIPES; i++ ) { // create pipe if ( (hPipe[i] = CreateNamedPipe("\\\\.\\pipe\\socket_pipe", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, NUM_PIPES, 0, 0, dwTime, NULL)) == INVALID_HANDLE_VALUE ) { printf("Create Pipe Error: %d\n", GetLastError()); return -1; } // Create Event if ( (hEvent[i] = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL ) { printf("Create Event Error: %d\n", GetLastError()); continue; } bRead[i] = FALSE; // Init OVERLAPPED ZeroMemory( &Ovlap[i], sizeof(OVERLAPPED) ); Ovlap[i].hEvent = hEvent[i]; // disconnect pipe if ( DisconnectNamedPipe( hPipe[i] ) == 0 ) { printf("DisconnectNamedPipe Error: %d\n", GetLastError()); return -1; } // connect pipe if ( ConnectNamedPipe( hPipe[i], &Ovlap[i] ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("Connect Name Pipe Error: %d\n", GetLastError()); CloseHandle(hPipe[i]); return -1; } } } printf("---------------------Server Is Start---------------------\n"); DWORD dwRet, dwPipe; while ( 1 ) { // waiting for Event if ( (dwRet = WaitForMultipleObjects( NUM_PIPES, hEvent, FALSE, INFINITE )) == WAIT_FAILED) { printf("Wait For MultipleObject Error: %d\n", GetLastError()); return -1; } dwPipe = dwRet - WAIT_OBJECT_0; ResetEvent( hEvent[dwPipe] ); // Get Info if ( GetOverlappedResult( hPipe[dwPipe], &Ovlap[dwPipe], &dwTransferred, TRUE ) == 0 ) { printf("GetOverlappedResult Error: %d\n", GetLastError()); if ( DisconnectNamedPipe( hPipe[dwPipe] ) == 0 ) { printf("DisconnectNamedPipe Error: %d\n", GetLastError()); return -1; } // Connect again if ( ConnectNamedPipe( hPipe[dwPipe], &Ovlap[dwPipe] ) == 0 ) { printf("DisconnectNamedPipe Error: %d\n", GetLastError()); return -1; } bRead[dwPipe] = FALSE; } else { if ( bRead[dwPipe] == FALSE ) { ZeroMemory( &Ovlap[dwPipe], sizeof(OVERLAPPED) ); Ovlap[dwPipe].hEvent = hEvent[dwPipe]; if ( ReadFile( hPipe[dwPipe], szBuffer[dwPipe], BUFFER_SIZE, NULL, &Ovlap[dwPipe] ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("ReadFile Error: %d\n", GetLastError()); return -1; } } bRead[dwPipe] = TRUE; } else { printf("Recevied %d Bytes", dwTransferred); ZeroMemory( &Ovlap[dwPipe], sizeof(OVERLAPPED) ); Ovlap[dwPipe].hEvent = hEvent[dwPipe]; if ( WriteFile( hPipe[dwPipe], szBuffer[dwPipe], dwTransferred, NULL, &Ovlap[dwPipe] ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("ReadFile Error: %d\n", GetLastError()); return -1; } } bRead[dwPipe] = FALSE; } } } for ( int i = 0; i < NUM_PIPES; i++ ) { CloseHandle(hPipe[i]); } system("pause"); return 0; } 客戶端: view plaincopy to clipboardprint? // PipeClient.cpp : Defines the entry point for the console application. // 管道通訊客服端 #include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <iostream> using namespace std; #define BUFFER_SIZE 256 #define PIPE "\\\\.\\pipe\\socket_pipe" int _tmain(int argc, _TCHAR* argv[]) { HANDLE hPipe; DWORD dwWrite; // waiting if ( WaitNamedPipe( PIPE, NMPWAIT_WAIT_FOREVER ) == FALSE ) { printf("WaitNamedPipe Error: %d\n", GetLastError()); return -1; } // create pipe if ( (hPipe = CreateFile( PIPE, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ) == INVALID_HANDLE_VALUE) { printf("CreateFile Error: %d\n", GetLastError()); return -1; } // send if ( WriteFile( hPipe, "This is Test Pipe", 17, &dwWrite, NULL ) == 0 ) { printf("CreateFile Error: %d\n", GetLastError()); CloseHandle( hPipe ); return -1; } DWORD dwRead; char szBuffer[BUFFER_SIZE]; if ( ReadFile( hPipe, szBuffer, BUFFER_SIZE, &dwRead, NULL ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("ReadFile Error: %d\n", GetLastError()); return -1; } } szBuffer[dwRead] = '\0'; printf("%s", szBuffer); system("pause"); // recv return 0; }
柄。 2) 呼叫WriteFile這個API函式,向郵槽寫入資料。 命名管道的實現: 服務端: 1) 使用API函式CreateNamedPipe,建立一個命名管道例項控制代碼。
2) 使用API函式ConnectNamedPipe,在命名管道例項上監聽客戶機連線請求。
3) 分別使用ReadFile和WriteFile這兩個API函式,從客戶機接收資料,或將資料發給客戶
機。
4) 使用API函式DisconnectNamedPipe,關閉命名管道連線。
5) 使用API函式CloseHandle,關閉命名管道例項控制代碼。 客戶端: 1) 用API函式WaitNamedPipe,等候一個命名管道例項可供自己使用。
2) 用API函式CreateFile,建立與命名管道的連線。
3) 用API函式WriteFile和ReadFile,分別向伺服器傳送資料,或從中接收資料。
4) 用API函式CloseHandle,關閉開啟的命名管道會話。 命名管道的程式碼實現: 服務端: view plaincopy to clipboardprint? // PipeServer.cpp : Defines the entry point for the console application. // 管道通訊伺服器 #include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <iostream> using namespace std; #define NUM_PIPES 5 #define BUFFER_SIZE 256 int _tmain(int argc, _TCHAR* argv[]) { DWORD dwTransferred; HANDLE hPipe[NUM_PIPES]; char szBuffer[NUM_PIPES][BUFFER_SIZE]; OVERLAPPED Ovlap[NUM_PIPES]; HANDLE hEvent[NUM_PIPES]; DWORD dwTime = 1000; BOOL bRead[NUM_PIPES]; for ( int i = 0; i < NUM_PIPES; i++ ) { // create pipe if ( (hPipe[i] = CreateNamedPipe("\\\\.\\pipe\\socket_pipe", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, NUM_PIPES, 0, 0, dwTime, NULL)) == INVALID_HANDLE_VALUE ) { printf("Create Pipe Error: %d\n", GetLastError()); return -1; } // Create Event if ( (hEvent[i] = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL ) { printf("Create Event Error: %d\n", GetLastError()); continue; } bRead[i] = FALSE; // Init OVERLAPPED ZeroMemory( &Ovlap[i], sizeof(OVERLAPPED) ); Ovlap[i].hEvent = hEvent[i]; // disconnect pipe if ( DisconnectNamedPipe( hPipe[i] ) == 0 ) { printf("DisconnectNamedPipe Error: %d\n", GetLastError()); return -1; } // connect pipe if ( ConnectNamedPipe( hPipe[i], &Ovlap[i] ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("Connect Name Pipe Error: %d\n", GetLastError()); CloseHandle(hPipe[i]); return -1; } } } printf("---------------------Server Is Start---------------------\n"); DWORD dwRet, dwPipe; while ( 1 ) { // waiting for Event if ( (dwRet = WaitForMultipleObjects( NUM_PIPES, hEvent, FALSE, INFINITE )) == WAIT_FAILED) { printf("Wait For MultipleObject Error: %d\n", GetLastError()); return -1; } dwPipe = dwRet - WAIT_OBJECT_0; ResetEvent( hEvent[dwPipe] ); // Get Info if ( GetOverlappedResult( hPipe[dwPipe], &Ovlap[dwPipe], &dwTransferred, TRUE ) == 0 ) { printf("GetOverlappedResult Error: %d\n", GetLastError()); if ( DisconnectNamedPipe( hPipe[dwPipe] ) == 0 ) { printf("DisconnectNamedPipe Error: %d\n", GetLastError()); return -1; } // Connect again if ( ConnectNamedPipe( hPipe[dwPipe], &Ovlap[dwPipe] ) == 0 ) { printf("DisconnectNamedPipe Error: %d\n", GetLastError()); return -1; } bRead[dwPipe] = FALSE; } else { if ( bRead[dwPipe] == FALSE ) { ZeroMemory( &Ovlap[dwPipe], sizeof(OVERLAPPED) ); Ovlap[dwPipe].hEvent = hEvent[dwPipe]; if ( ReadFile( hPipe[dwPipe], szBuffer[dwPipe], BUFFER_SIZE, NULL, &Ovlap[dwPipe] ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("ReadFile Error: %d\n", GetLastError()); return -1; } } bRead[dwPipe] = TRUE; } else { printf("Recevied %d Bytes", dwTransferred); ZeroMemory( &Ovlap[dwPipe], sizeof(OVERLAPPED) ); Ovlap[dwPipe].hEvent = hEvent[dwPipe]; if ( WriteFile( hPipe[dwPipe], szBuffer[dwPipe], dwTransferred, NULL, &Ovlap[dwPipe] ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("ReadFile Error: %d\n", GetLastError()); return -1; } } bRead[dwPipe] = FALSE; } } } for ( int i = 0; i < NUM_PIPES; i++ ) { CloseHandle(hPipe[i]); } system("pause"); return 0; } 客戶端: view plaincopy to clipboardprint? // PipeClient.cpp : Defines the entry point for the console application. // 管道通訊客服端 #include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <iostream> using namespace std; #define BUFFER_SIZE 256 #define PIPE "\\\\.\\pipe\\socket_pipe" int _tmain(int argc, _TCHAR* argv[]) { HANDLE hPipe; DWORD dwWrite; // waiting if ( WaitNamedPipe( PIPE, NMPWAIT_WAIT_FOREVER ) == FALSE ) { printf("WaitNamedPipe Error: %d\n", GetLastError()); return -1; } // create pipe if ( (hPipe = CreateFile( PIPE, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ) == INVALID_HANDLE_VALUE) { printf("CreateFile Error: %d\n", GetLastError()); return -1; } // send if ( WriteFile( hPipe, "This is Test Pipe", 17, &dwWrite, NULL ) == 0 ) { printf("CreateFile Error: %d\n", GetLastError()); CloseHandle( hPipe ); return -1; } DWORD dwRead; char szBuffer[BUFFER_SIZE]; if ( ReadFile( hPipe, szBuffer, BUFFER_SIZE, &dwRead, NULL ) == 0 ) { if ( GetLastError() != ERROR_IO_PENDING ) { printf("ReadFile Error: %d\n", GetLastError()); return -1; } } szBuffer[dwRead] = '\0'; printf("%s", szBuffer); system("pause"); // recv return 0; }