管道是进程通信用的共享内存的一部分,有两种用于双向通信的管道:匿名管道和命名管道。前者使得有亲属关系的进程能传递信息,一般常用来重定向子进程的标准输入或输出,这样子进程就可以与其父进程交换数据。为了能双向通信,必须创建两个匿名管道。父进程使用管道的写句柄写入数据到第一个管道,而子进程使用管道的读句柄从第一个管道中读出数据。类似地,子进程写入数据到第二个管道,而父进程从第二个管道读取数据。匿名管道不能在网络中使用,也不能在彼此无关的进程间使用。

 

命名管道用来在彼此间无关的进程和不同计算机上的进程之间传输数据。一般地,命名管道服务器进程使用一个众所周知的名称或能通知给各个客户端的名称来创建一个命名管道。命名管道客户进程只要知道服务器创建的管道的名称就可以打开这个管道的另一端。当服务器和客户都连接到管道上后,他们就可以通过对管道的读写来交换数据。

 

CreatePipe函数创建一个匿名管道,返回两个句柄:管道读句柄和管道写句柄。读句柄对管道只有只读权限,写句柄对管道只有只写权限。为了使用管道通信,管道服务器必须传递管道句柄给另一个进程,一般这通过继承来实现。这就是说,进程允许句柄能被子进程继承。进程也可以使用DuplicateHandle函数复制一个管道句柄并使用一些进程间通信方法,比如DDE或共享内存,将管道句柄传递给一个无关的进程。

 

管道服务器既可以传送读句柄或写句柄给管道客户,这取决于客户使用匿名管道发送还是接收信息。为了从管道读数据,客户在ReadFile函数中使用管道的读句柄。若有另一个进程在往管道中写数据时,ReadFile函数立马返回。若管道的所有的写句柄已经被关闭或读操作完成前发生错误,ReadFile函数也立马返回。

 

为了往管道中写数据,在WriteFile函数中使用管道的写句柄。直到指定数量的字节被写入管道中前或错误发生时,WriteFile函数才返回。若管道缓冲区满了而还有数据要待写入,WriteFile就会等另一个进程从管道中读取出数据后,从而空出更多的缓冲区空间时才返回。管道服务器在调用CreatePipe函数时指定管道的缓冲区大小。

 

匿名管道不支持异步读写操作(overlapped)。这意味着你不能在匿名管道上使用ReadFileExWriteFileEx。此外,当使用匿名管道时,ReadFileWriteFilelpOverlapped参数会被忽略。

 

当所有的管道句柄(读句柄和写句柄)都被关闭后,匿名管道才不存在。进程可以使用CloseHandle函数来关闭管道句柄。当进程终止时,所有的管道句柄也被关闭。

 

匿名管道使用一个拥有唯一名字的命名管道实现,因此,对于那些需要一个命名管道句柄的函数来说,你可以传递匿名管道的句柄给它们。

 

管道服务器通过如下方式控制它的句柄能否被继承:

 

1,  CreatePipe函数接受一个SECURITY_ATTRIBUTES结构体,若管道服务器将bInheritHandle设置为TRUE,则创建的句柄可以被继承。

 

2,使用DuplicateHandle函数来改变一个管道句柄的继承性。

 

3CreateProcess函数允许管道服务器指明子进程是否继承或不继承它所有的可继承的句柄。

 

当子进程继承了一个管道句柄,系统允许进程访问管道。然而,父进程必须将句柄值交流给子进程。这点父进程一般通过重定向标准输出到子进程来实现,步骤如下:

 

1,  调用GetStdHandle函数获取当前的标准输出句柄,保存这个句柄以便在子进程创建完后可以恢复原来的标准输出句柄。

 

2,  调用SetStdHandle函数设置标准输出句柄为管道的写句柄,现在父进程可以创建子进程了。

 

3,  调用CloseHandle函数关闭管道的写句柄,当子进程继承写句柄后,父进程就不需要它的拷贝了。

 

4,  调用SetStdHandle恢复原来的标准输出句柄。

 

子进程使用GetStdHandle函数来得到它的标准输出句柄,而现在它是管道的写端的句柄。子进程使用WriteFile函数将它的数据写到管道中,当子进程使用完管道后,它应该调用CloseHandle来关闭管道句柄或直接终止进程,后者会自动关闭句柄的。

 

      父进程使用ReadFile函数来从管道中接收数据。数据是以字节流的形式写入匿名句柄中的,这就意味着从管道中读数据的父进程可以在几次写数据操作中无法分辨开来,除非父子进程使用一个协议来指明写操作何时完成。当管道所有的写句柄关闭后,ReadFile函数返回0.对于父进程来说,重要的一点是,在调用ReadFile前,应该关闭管道的写端的所有句柄。若这个不做的话,ReadFile操作就无法返回0,因为父进程还有到管道写端的打开句柄。

 

      重定向标准输入句柄类似于重定向输出句柄,管道的读句柄作为子进程的标准输入句柄使用。这时,父进程必须确保子进程没有继承管道的写句柄。若不然,子进程的ReadFile操作无法返回0,因为子进程有到管道的写端的打开句柄。

父进程:

 

None.gif#include <windows.h> 
None.gif#include <tchar.h>
None.gif#include <stdio.h> 
None.gif 
None.gif#define BUFSIZE 4096 
None.gif 
None.gifHANDLE hChildStdinRd, hChildStdinWr,  
None.gif   hChildStdoutRd, hChildStdoutWr, 
None.gif   hInputFile, hStdout;
None.gif 
None.gifBOOL CreateChildProcess(VOID); 
None.gifVOID WriteToPipe(VOID); 
None.gifVOID ReadFromPipe(VOID); 
None.gifVOID ErrorExit(LPSTR); 
None.gif 
None.gifint _tmain(int argc, TCHAR *argv[]) 
ExpandedBlockStart.gifContractedBlock.gifdot.gif
InBlock.gif   SECURITY_ATTRIBUTES saAttr; 
InBlock.gif   BOOL fSuccess; 
InBlock.gif 
InBlock.gif// Set the bInheritHandle flag so pipe handles are inherited. 
InBlock.gif 
InBlock.gif   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
InBlock.gif   saAttr.bInheritHandle = TRUE; 
InBlock.gif   saAttr.lpSecurityDescriptor = NULL; 
InBlock.gif
InBlock.gif// Get the handle to the current STDOUT. 
InBlock.gif 
InBlock.gif   hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
InBlock.gif 
InBlock.gif// Create a pipe for the child process's STDOUT. 
InBlock.gif 
InBlock.gif   if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) 
InBlock.gif      ErrorExit("Stdout pipe creation failed\n"); 
InBlock.gif
InBlock.gif// Ensure the read handle to the pipe for STDOUT is not inherited.
InBlock.gif
InBlock.gif   SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0);
InBlock.gif
InBlock.gif// Create a pipe for the child process's STDIN. 
InBlock.gif 
InBlock.gif   if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) 
InBlock.gif      ErrorExit("Stdin pipe creation failed\n"); 
InBlock.gif
InBlock.gif// Ensure the write handle to the pipe for STDIN is not inherited. 
InBlock.gif 
InBlock.gif   SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, 0);
InBlock.gif 
InBlock.gif// Now create the child process. 
InBlock.gif   
InBlock.gif   fSuccess = CreateChildProcess();
InBlock.gif   if (! fSuccess) 
InBlock.gif      ErrorExit("Create process failed with"); 
InBlock.gif
InBlock.gif// Get a handle to the parent's input file. 
InBlock.gif 
InBlock.gif   if (argc == 1) 
InBlock.gif      ErrorExit("Please specify an input file"); 
InBlock.gif
InBlock.gif   printf( "\nContents of %s:\n\n", argv[1]);
InBlock.gif
InBlock.gif   hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, 
InBlock.gif      OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); 
InBlock.gif
InBlock.gif   if (hInputFile == INVALID_HANDLE_VALUE) 
InBlock.gif      ErrorExit("CreateFile failed"); 
InBlock.gif 
InBlock.gif// Write to pipe that is the standard input for a child process. 
InBlock.gif 
InBlock.gif   WriteToPipe(); 
InBlock.gif 
InBlock.gif// Read from pipe that is the standard output for child process. 
InBlock.gif 
InBlock.gif   ReadFromPipe(); 
InBlock.gif 
InBlock.gif   return 0; 
ExpandedBlockEnd.gif
None.gif 
None.gifBOOL CreateChildProcess() 
ExpandedBlockStart.gifContractedBlock.gifdot.gif
InBlock.gif   TCHAR szCmdline[]=TEXT("child");
InBlock.gif   PROCESS_INFORMATION piProcInfo; 
InBlock.gif   STARTUPINFO siStartInfo;
InBlock.gif   BOOL bFuncRetn = FALSE; 
InBlock.gif 
InBlock.gif// Set up members of the PROCESS_INFORMATION structure. 
InBlock.gif 
InBlock.gif   ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
InBlock.gif 
InBlock.gif// Set up members of the STARTUPINFO structure. 
InBlock.gif 
InBlock.gif   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
InBlock.gif   siStartInfo.cb = sizeof(STARTUPINFO); 
InBlock.gif   siStartInfo.hStdError = hChildStdoutWr;
InBlock.gif   siStartInfo.hStdOutput = hChildStdoutWr;
InBlock.gif   siStartInfo.hStdInput = hChildStdinRd;
InBlock.gif   siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
InBlock.gif 
InBlock.gif// Create the child process. 
InBlock.gif    
InBlock.gif   bFuncRetn = CreateProcess(NULL, 
InBlock.gif      szCmdline,     // command line 
InBlock.gif      NULL,          // process security attributes 
InBlock.gif      NULL,          // primary thread security attributes 
InBlock.gif      TRUE,          // handles are inherited 
InBlock.gif      0,             // creation flags 
InBlock.gif      NULL,          // use parent's environment 
InBlock.gif      NULL,          // use parent's current directory 
InBlock.gif      &siStartInfo,  // STARTUPINFO pointer 
InBlock.gif      &piProcInfo);  // receives PROCESS_INFORMATION 
InBlock.gif   
InBlock.gif   if (bFuncRetn == 0) 
InBlock.gif      ErrorExit("CreateProcess failed\n");
InBlock.gif   else 
ExpandedSubBlockStart.gifContractedSubBlock.gif   dot.gif{
InBlock.gif      CloseHandle(piProcInfo.hProcess);
InBlock.gif      CloseHandle(piProcInfo.hThread);
InBlock.gif      return bFuncRetn;
ExpandedSubBlockEnd.gif   }
ExpandedBlockEnd.gif}
None.gif 
None.gifVOID WriteToPipe(VOID) 
ExpandedBlockStart.gifContractedBlock.gifdot.gif
InBlock.gif   DWORD dwRead, dwWritten; 
InBlock.gif   CHAR chBuf[BUFSIZE]; 
InBlock.gif 
InBlock.gif// Read from a file and write its contents to a pipe. 
InBlock.gif 
InBlock.gif   for (;;) 
ExpandedSubBlockStart.gifContractedSubBlock.gif   dot.gif
InBlock.gif      if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) || 
InBlock.gif         dwRead == 0) break; 
InBlock.gif      if (! WriteFile(hChildStdinWr, chBuf, dwRead, 
InBlock.gif         &dwWritten, NULL)) break; 
ExpandedSubBlockEnd.gif   } 
InBlock.gif 
InBlock.gif// Close the pipe handle so the child process stops reading. 
InBlock.gif 
InBlock.gif   if (! CloseHandle(hChildStdinWr)) 
InBlock.gif      ErrorExit("Close pipe failed\n"); 
ExpandedBlockEnd.gif
None.gif 
None.gifVOID ReadFromPipe(VOID) 
ExpandedBlockStart.gifContractedBlock.gifdot.gif
InBlock.gif   DWORD dwRead, dwWritten; 
InBlock.gif   CHAR chBuf[BUFSIZE]; 
InBlock.gif
InBlock.gif// Close the write end of the pipe before reading from the 
InBlock.gif// read end of the pipe. 
InBlock.gif 
InBlock.gif   if (!CloseHandle(hChildStdoutWr)) 
InBlock.gif      ErrorExit("Closing handle failed"); 
InBlock.gif 
InBlock.gif// Read output from the child process, and write to parent's STDOUT. 
InBlock.gif 
InBlock.gif   for (;;) 
ExpandedSubBlockStart.gifContractedSubBlock.gif   dot.gif
InBlock.gif      if( !ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead, 
InBlock.gif         NULL) || dwRead == 0) break; 
InBlock.gif      if (! WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL)) 
InBlock.gif         break; 
ExpandedSubBlockEnd.gif   } 
ExpandedBlockEnd.gif
None.gif 
None.gifVOID ErrorExit (LPSTR lpszMessage) 
ExpandedBlockStart.gifContractedBlock.gifdot.gif
InBlock.gif   fprintf(stderr, "%s\n", lpszMessage); 
InBlock.gif   ExitProcess(0); 
ExpandedBlockEnd.gif}
None.gif

 

子进程:

None.gif#include <windows.h> 
None.gif
None.gif#define BUFSIZE 4096 
None.gif 
None.gifVOID main(VOID) 
ExpandedBlockStart.gifContractedBlock.gifdot.gif
InBlock.gif   CHAR chBuf[BUFSIZE]; 
InBlock.gif   DWORD dwRead, dwWritten; 
InBlock.gif   HANDLE hStdin, hStdout; 
InBlock.gif   BOOL fSuccess; 
InBlock.gif 
InBlock.gif   hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
InBlock.gif   hStdin = GetStdHandle(STD_INPUT_HANDLE); 
InBlock.gif   if ((hStdout == INVALID_HANDLE_VALUE) || 
InBlock.gif      (hStdin == INVALID_HANDLE_VALUE)) 
InBlock.gif      ExitProcess(1); 
InBlock.gif 
InBlock.gif   for (;;) 
ExpandedSubBlockStart.gifContractedSubBlock.gif   dot.gif
InBlock.gif   // Read from standard input. 
InBlock.gif      fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL); 
InBlock.gif      if (! fSuccess || dwRead == 0) 
InBlock.gif         break; 
InBlock.gif 
InBlock.gif   // Write to standard output. 
InBlock.gif      fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL); 
InBlock.gif      if (! fSuccess) 
InBlock.gif         break; 
ExpandedSubBlockEnd.gif   } 
ExpandedBlockEnd.gif}
None.gif