何为“管道”?
“管道”是进程间通讯的一段共享内存区域。创建管道的进程成为管道服务器,连接到管道上的进程成为管道客户端。一个进程向管道写数据,其他进程可以从管道中读取数据。
“管道的分类”
管道分为两种,匿名管道和命名管道。匿名管道比命名管道需要的开销要小,但是提供的功能要少。管道在这里的含义暗示着它是一种连接信息的管子。管子有两端,单工通讯的管道允许在写端的进程把信息写入管子,在读端的进程读取管道中的信息。全双工通讯的管道允许在两端进行读写。
匿名管道提供单工通讯,没有名称。并且只能用于本地,不能通过网络通讯。
命名管道是一个有名称,能提供单工或全双工通讯的管子。它允许一个管道服务器,多个管道客户端。所有命名管道的实例共享一个管道名称,但是每个实例有它自己的缓冲区和句柄,并且为每个服务器/客户端通讯提供单独的信息传输渠道.这种方式允许多个管道客户端同时使用命名管道.任何命名管道都可以被任何进程访问,但是受制与安全检测策略.因此命名管道可以方便的区分相关与不相关的进程.
任何进程都可以作为服务器或者客户端,这使得p2p通信成为可能.这里管道服务器是指创建管道的进程,管道客户端是指连接到一个命名管道实例上的进程.管道服务器端使用CreateNamedPipe创建命名管道,使用ConnectNamedPipe接收连接请求.管道客户端使用CreateFile 和CallNamedPipe连接命名管道.
命名管道可以为本地或者通过网络与远程电脑中的进程提供通讯.如果你仅仅想让命名管道运行在本地,可以用本地RPC策略或者禁止访问NT AUTHORITY\NETWORK.
“匿名管道”使用示例
代码要实现的功能就是创建两个控制台程序,一个控制台写消息,另一个控制台收消息。这是子父进程通信中匿名管道的典型用法,我们先直观看看这个示例是怎么工作的:
左边是父控制台,右边是子控制台。左边输入字符,右边就会显示出来:
下面是代码:
1 #include "UnNamedPipe.h" 2 #include <iostream> 3 4 using namespace std; 5 6 HANDLE g_hReadPipe; 7 HANDLE g_hWritePipe; 8 9 int main() 10 { 11 LPTSTR errbuff; 12 char strBuff[256] = {0}; 13 char* QUITCHAR = "q"; 14 CUnNamedPipe myPipe; 15 SECURITY_ATTRIBUTES saAttr; 16 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 17 saAttr.bInheritHandle = TRUE; 18 saAttr.lpSecurityDescriptor = NULL; 19 STARTUPINFO siStartInfo; 20 PROCESS_INFORMATION piProcInfo; 21 DWORD nWriteTo; 22 TCHAR szAppName[] = TEXT("C:\\Users\\user\\Documents\\Visual Studio 2010\\Projects\\PipeWorkShop\\Debug\\AnonymousPipeClientTest.exe"); 23 if(!myPipe.CreatePipe(g_hReadPipe, g_hWritePipe, saAttr, 0)) 24 { 25 DWORD d = GetLastError(); 26 FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | 27 FORMAT_MESSAGE_IGNORE_INSERTS | 28 FORMAT_MESSAGE_FROM_SYSTEM, 29 NULL, 30 d, 31 LANG_NEUTRAL, 32 (LPTSTR) & errbuff, 33 0 , 34 NULL ); 35 cout<<"can not create pipe!"<<endl; 36 return 1; 37 } 38 39 if(!SetHandleInformation(g_hReadPipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) 40 { 41 cout<<"set handle property error!"<<endl; 42 } 43 /*if(!SetHandleInformation(g_hWritePipe, HANDLE_FLAG_INHERIT, 0)) 44 { 45 cout<<"set handle property error!"<<endl; 46 }*/ 47 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); 48 siStartInfo.cb = sizeof(STARTUPINFO); 49 siStartInfo.hStdInput = g_hReadPipe; 50 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 51 siStartInfo.dwFlags |= STARTF_USESTDHANDLES; 52 53 if(!CreateProcess(szAppName, NULL, NULL, NULL, TRUE,CREATE_NEW_CONSOLE, NULL,NULL, &siStartInfo, &piProcInfo)) 54 { 55 DWORD d = GetLastError(); 56 FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | 57 FORMAT_MESSAGE_IGNORE_INSERTS | 58 FORMAT_MESSAGE_FROM_SYSTEM, 59 NULL, 60 d, 61 LANG_NEUTRAL, 62 (LPTSTR) & errbuff, 63 0 , 64 NULL ); 65 66 cout<<"can't create process:"<<szAppName<<endl; 67 cout<<errbuff; 68 return 0; 69 } 70 cout<<"press q to quit, others to show!"<<endl; 71 while (cin>>strBuff ) 72 { 73 while(strBuff[0]!=0) 74 { 75 if(!WriteFile(g_hWritePipe, strBuff, sizeof strBuff, &nWriteTo, NULL)) 76 { 77 cout<<"write file error!"<<endl; 78 break; 79 } 80 if(strcmp(strBuff, QUITCHAR) == 0) 81 { 82 return 0;; 83 } 84 ZeroMemory(strBuff, sizeof(strBuff)); 85 } 86 87 } 88 CloseHandle(piProcInfo.hProcess); 89 CloseHandle(piProcInfo.hThread); 90 91 myPipe.ClosePipe(g_hReadPipe); 92 myPipe.ClosePipe(g_hWritePipe); 93 94 return 0; 95 }
1 #include <Windows.h> 2 #include <iostream> 3 4 using namespace std; 5 int main() 6 { 7 HANDLE hStdin, hStdout; 8 char buff[256] = {0}; 9 char* QUIT = "q"; 10 DWORD dwRead; 11 DWORD dwWrite; 12 hStdin = GetStdHandle(STD_INPUT_HANDLE); 13 hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 14 if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE) 15 { 16 return 1; 17 } 18 cout<<"client is working!"<<endl; 19 while(1) 20 { 21 if(ReadFile(hStdin, buff, 256, &dwRead, NULL) && buff[0] != 0) 22 { 23 if(strcmp(buff,QUIT) == 0) 24 return 0; 25 else 26 { 27 cout<<buff<<endl; 28 //WriteFile(hStdout, buff, 256, &dwWrite, NULL); there is someting interesting if you use this instead of before one. 29 ZeroMemory(buff, sizeof buff); 30 } 31 32 } 33 34 Sleep(500); 35 } 36 cout<<"client will shutdown in 3 sec!"<<endl; 37 Sleep(3000); 38 return 0; 39 }
接口代码:
1 /******************************************************************** 2 created: 2012/08/11 3 file name: IPipe.h 4 author: baesky 5 http://www.cnblogs.com/Baesky/ 6 purpose: Give a public interface. 7 *********************************************************************/ 8 9 #pragma once 10 #include <Windows.h> 11 class IPipe 12 { 13 public: 14 virtual bool CreatePipe(HANDLE& hReadPipe, HANDLE& hWritePipe, SECURITY_ATTRIBUTES& lpPipeAttributes, DWORD nBuffSize) = 0; 15 virtual bool ClosePipe(HANDLE hPipe) = 0; 16 };
1 #pragma once 2 #include "IPipe.h" 3 4 5 class CUnNamedPipe:public IPipe 6 { 7 public: 8 CUnNamedPipe(void); 9 ~CUnNamedPipe(void); 10 11 bool CreatePipe(HANDLE& hReadPipe, HANDLE& hWritePipe, SECURITY_ATTRIBUTES& lpPipeAttributes, DWORD nBuffSize); 12 bool ClosePipe(HANDLE hPipe); 13 };
1 #include "UnNamedPipe.h" 2 3 4 CUnNamedPipe::CUnNamedPipe(void) 5 { 6 } 7 8 9 CUnNamedPipe::~CUnNamedPipe(void) 10 { 11 } 12 13 bool CUnNamedPipe::CreatePipe(HANDLE& hReadPipe, HANDLE& hWritePipe, SECURITY_ATTRIBUTES& lpPipeAttributes, DWORD nBuffSize) 14 { 15 return ::CreatePipe(&hReadPipe, &hWritePipe, &lpPipeAttributes, nBuffSize); 16 } 17 18 bool CUnNamedPipe::ClosePipe(HANDLE hPipe) 19 { 20 return CloseHandle(hPipe); 21 }