前面已經使用郵槽實現過進程間通信:http://www.cnblogs.com/jzincnblogs/p/5192654.html ,這里使用命名管道實現進程間通信。
與郵槽不同的是,命名管道在進程間傳輸數據是基於連接且可靠的傳輸方式,所以命名管道傳輸數據只能一對一。使用命名管道的步驟如下:
①創建命名管道,命名管道通過調用函數CreateNamedPipe()創建,函數原型如下:
1 HANDLE WINAPI CreateNamedPipe( 2 _In_ LPCTSTR lpName, 3 _In_ DWORD dwOpenMode, 4 _In_ DWORD dwPipeMode, 5 _In_ DWORD nMaxInstances, 6 _In_ DWORD nOutBufferSize, 7 _In_ DWORD nInBufferSize, 8 _In_ DWORD nDefaultTimeOut, 9 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes 10 );
各參數的設置方法可參考MSDN:https://msdn.microsoft.com/zh-cn/biztalk/aa365150(v=vs.80)
②連接命名管道。當用戶成功創建命名管道后便可調用相關函數連接命名管道,對於服務器而言,可以調用函數ConnectNamedPipe()等待客戶端的連接請求,函數原型如下:
1 BOOL WINAPI ConnectNamedPipe( 2 _In_ HANDLE hNamedPipe, 3 _Inout_opt_ LPOVERLAPPED lpOverlapped 4 );
參數的設置方法:https://msdn.microsoft.com/zh-cn/biztalk/aa365150(v=vs.80)
對於客戶端而言,在連接服務器創建的命名管道前需要判斷該命名管道是否可用,可調用函數WaitNamedPipe()實現,函數使用方法可參考MSDN:https://msdn.microsoft.com/zh-cn/subscriptions/aa365800
當WaitNamedPipe()調用成功后,便可使用CreateFile()將命名管道打開已獲得管道的句柄。
③讀寫命名管道,對命名管道的讀寫操作利用函數ReadFile()和WriteFile()完成,與上一篇的郵槽類似。
服務器和客戶端的實現代碼如下:
服務器端:
1 //server 2 //命名管道采用基於連接的可靠傳輸方式,只能一對一傳輸 3 #include <windows.h> 4 #include <iostream> 5 6 #define BUF_SIZE 1024 7 8 using std::cerr; 9 using std::cout; 10 using std::endl; 11 12 int main() 13 { 14 HANDLE h_pipe; 15 char buf_msg[BUF_SIZE]; 16 DWORD num_rcv; //實際接收到的字節數 17 //創建命名管道,命名為MyPipe,消息只能從客戶端流向服務器,讀寫數據采用阻塞模式,字節流形式,超時值置為0表示采用默認的50毫秒 18 h_pipe = ::CreateNamedPipe("\\\\.\\pipe\\MyPipe", PIPE_ACCESS_INBOUND, PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUF_SIZE, BUF_SIZE, 0, nullptr); 19 if (h_pipe == INVALID_HANDLE_VALUE) 20 { 21 cerr << "Failed to create named pipe!Error code: " << ::GetLastError() << "\n"; 22 system("pause"); 23 return 1; 24 } 25 else 26 { 27 cout << "Named pipe created successfully...\n"; 28 } 29 //等待命名管道客戶端連接 30 if (::ConnectNamedPipe(h_pipe, nullptr)) 31 { 32 cout << "A client connected...\n"; 33 memset(buf_msg, 0, BUF_SIZE); 34 //讀取數據 35 if (::ReadFile(h_pipe, buf_msg, BUF_SIZE, &num_rcv, nullptr)) 36 { 37 cout << "Message received: " << buf_msg << "\n"; 38 } 39 else 40 { 41 cerr << "Failed to receive message!Error code: " << ::GetLastError() << "\n"; 42 ::CloseHandle(h_pipe); 43 ::system("pause"); 44 return 1; 45 } 46 } 47 ::CloseHandle(h_pipe); 48 ::system("pause"); 49 return 0; 50 }
客戶端:
1 //client 2 #include <windows.h> 3 #include <iostream> 4 5 #define BUF_SIZE 1024 6 7 using std::cerr; 8 using std::cout; 9 using std::endl; 10 11 int main() 12 { 13 HANDLE h_pipe; 14 char buf_msg[] = "Test for named pipe..."; 15 DWORD num_rcv; //實際接收到的字節數 16 cout << "Try to connect named pipe...\n"; 17 //連接命名管道 18 if (::WaitNamedPipe("\\\\.\\pipe\\MyPipe", NMPWAIT_WAIT_FOREVER)) 19 { 20 //打開指定命名管道 21 h_pipe = ::CreateFile("\\\\.\\pipe\\MyPipe", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 22 if (h_pipe == INVALID_HANDLE_VALUE) 23 { 24 cerr << "Failed to open the appointed named pipe!Error code: " << ::GetLastError() << "\n"; 25 ::system("pause"); 26 return 1; 27 } 28 else 29 { 30 if (::WriteFile(h_pipe, buf_msg, BUF_SIZE, &num_rcv, nullptr)) 31 { 32 cout << "Message sent successfully...\n"; 33 } 34 else 35 { 36 cerr << "Failed to send message!Error code: " << ::GetLastError() << "\n"; 37 ::CloseHandle(h_pipe); 38 ::system("pause"); 39 return 1; 40 } 41 } 42 ::CloseHandle(h_pipe); 43 } 44 ::system("pause"); 45 return 0; 46 }
