1.匿名管道的介绍:
既然是匿名管道的话,自然,就是没有名字的管道了,还有一种管道呢,叫做命名管道,命名管道的功能是很强大的,匿名管道在命名管道面前,功能那是简陋的不行的,至于命名管道的话,以后才介绍,匿名管道正因为提供的功能很单一,所以它所需要的系统的开销也就比命名管道小很多,在本地机器上可以使用匿名管道来实现父进程和子进程之间的通信,这里需要注意两点,第一就是在本地机器上,这是因为匿名管道不支持跨网络之间的两个进程之间的通信,第二就是实现的是父进程和子进程之间的通信,而不是任意的两个进程。然后得话还顺便介绍匿名管道的另外一种功能,其通过匿名管道可以实现子进程输出的重定向。重定向后面文章会介绍。下面介绍一下匿名管道的使用:
(1)匿名管道主要用于本地父进程和子进程之间的通信,
(2)在父进程中的话,首先是要创建一个匿名管道,
(3)在创建匿名管道成功后,可以获取到对这个匿名管道的读写句柄,
(4)然后父进程就可以向这个匿名管道中写入数据和读取数据了,
(5)但是如果要实现的是父子进程通信的话,那么还必须在父进程中创建一个子进程,
(6)同时,这个子进程必须能够继承和使用父进程的一些公开的句柄,
(7)为什么呢?
(8)因为在子进程中必须要使用父进程创建的匿名管道的读写句柄,
(9)通过这个匿名管道才能实现父子进程的通信,所以必须继承父进程的公开句柄。
(10)同时在创建子进程的时候,
(11)必须将子进程的标准输入句柄设置为父进程中创建匿名管道时得到的读管道句柄,
(12)将子进程的标准输出句柄设置为父进程中创建匿名管道时得到的写管道句柄。
(13)然后在子进程就可以读写匿名管道了。
2 实例:
当前有sample.cpp, sample.exe, sample.in这三个文件,sample.exe为sample.cpp的执行程序,sample.cpp只是一个简单的程序示例(简单求和),如下:
代码:
32 433
542 657
0 0
#include <iostream>
using namespace std;
int main()
{
int a, b ;
while ( cin >> a >> b && ( a || b ) )
cout << a + b << endl ;
return 0;
}
Sample.in文件是输入文件,内容:
32 433
542 657
0 0
流程分析:实际这个实验中包含两个部分,把输入数据重定向到sample.exe 和把输出数据重定向到sample.out。在命令行下可以很简单的实现这个功能“sample <sample.in >sample.out”,这个命令也是利用管道特性实现的,现在我们就根据异步管道的实现原理自己来实现这个功能。
管道是基于半双工(单向)的,这里有两个重定向的过程,显然需要创建两个管道,下面给出流程图:
匿名管道实现的流程图说明:
1)。父进程是我们需要实现的,其中需要创建管道A,管道B,和子进程,整个实现流程分为4个操作。
2)。管道A:输入管道
3)。管道B:输出管道
4)。操作A:把输入文件sample.in的数据写入输入管道(管道A)
5)。操作B:子进程从输入管道中读取数据,作为该进程的加工原料。通常,程序的输入数据由标准的输入设备输入,这里实现输入重定向,即把输入管道作为输入设备。
6)。操作C:子进程把加工后的成品(输出数据)输出到输出管道。通常,程序的输出数据会输出到标准的输出设备,一般为屏幕,这里实现输出重定向,即把输出管道作为输出设备。
7)。操作D:把输出管道的数据写入输出文件
需要注意的是,管道的本质只是一个共享的内存区域。这个实验中,管道区域处于父进程的地址空间中,父进程的作用是提供环境和资源,并协调子进程进行加工。
程序源码:
1)。父进程是我们需要实现的,其中需要创建管道A,管道B,和子进程,整个实现流程分为4个操作。
2)。管道A:输入管道
3)。管道B:输出管道
4)。操作A:把输入文件sample.in的数据写入输入管道(管道A)
5)。操作B:子进程从输入管道中读取数据,作为该进程的加工原料。通常,程序的输入数据由标准的输入设备输入,这里实现输入重定向,即把输入管道作为输入设备。
6)。操作C:子进程把加工后的成品(输出数据)输出到输出管道。通常,程序的输出数据会输出到标准的输出设备,一般为屏幕,这里实现输出重定向,即把输出管道作为输出设备。
7)。操作D:把输出管道的数据写入输出文件
需要注意的是,管道的本质只是一个共享的内存区域。这个实验中,管道区域处于父进程的地址空间中,父进程的作用是提供环境和资源,并协调子进程进行加工。
程序源码:
代码:
#include<windows.h>
#include<iostream>
using namespace std;
const int BUFSIZE_=4096;
HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
hChildStdoutRd,hChildStdoutWr,hChildStdoutRdDup,
hSaveStdin, hSaveStdout;
bool CreateChildProcess(LPTSTR);
void WriteToPipe(LPTSTR);
void ReadFromPipe(LPTSTR);
void ErrorExit(LPTSTR );
int main(int argc,char* argv[])
{
if(argc!=4)
return -1;
LPTSTR lpProgram=new char[strlen(argv[1])];
strcpy(lpProgram,argv[1]);
LPTSTR lpInputFile = new char[ strlen(argv[2]) ];
strcpy ( lpInputFile, argv[2] ) ;
LPTSTR lpOutputFile = new char[ strlen(argv[3]) ] ;
strcpy ( lpOutputFile, argv[3] ) ;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
/************************************************
* redirecting child process's STDOUT *
************************************************/
hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
ErrorExit("Stdout pipe creation failed/n");
if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
ErrorExit("Redirecting STDOUT failed");
bool fSuccess = DuplicateHandle(
GetCurrentProcess(),
hChildStdoutRd,
GetCurrentProcess(),
&hChildStdoutRdDup ,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if( !fSuccess )
ErrorExit("DuplicateHandle failed");
CloseHandle(hChildStdoutRd);
/************************************************
* redirecting child process's STDIN *
************************************************/
hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
ErrorExit("Stdin pipe creation failed/n");
if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
ErrorExit("Redirecting Stdin failed");
fSuccess = DuplicateHandle(
GetCurrentProcess(),
hChildStdinWr,
GetCurrentProcess(),
&hChildStdinWrDup,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (! fSuccess)
ErrorExit("DuplicateHandle failed");
CloseHandle(hChildStdinWr);
/************************************************
* 创建子进程(即启动SAMPLE.EXE) *
************************************************/
fSuccess = CreateChildProcess( lpProgram );
if ( !fSuccess )
ErrorExit("Create process failed");
// 父进程输入输出流的还原设置
if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
ErrorExit("Re-redirecting Stdin failed/n");
if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
ErrorExit("Re-redirecting Stdout failed/n");
WriteToPipe( lpInputFile ) ;
ReadFromPipe( lpOutputFile );
delete lpProgram ;
delete lpInputFile ;
delete lpOutputFile ;
return 0;
}
bool CreateChildProcess(LPTSTR lpProgram)
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
bool bFuncRetn = FALSE;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
bFuncRetn = CreateProcess ( NULL, lpProgram, NULL, NULL, TRUE,
0, NULL, NULL, &siStartInfo, &piProcInfo);
if (bFuncRetn == 0)
{
ErrorExit("CreateProcess failed/n");
return 0;
}
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
void WriteToPipe(LPSTR lpInputFile)
{
HANDLE hInputFile = CreateFile(lpInputFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hInputFile == INVALID_HANDLE_VALUE)
{
cout<<"open file error!"<<endl;
return ;
}
DWORD fileSize = GetFileSize(hInputFile,NULL); //得到文件的大小;
bool fSuccess ;
DWORD dwRead, dwWritten;
//DWORD filesize=GetFileSize(hInputFile,NULL);
CHAR chBuf[fileSize] = {0} ;
DWORD dwBytesToRead = fileSize;
dwRead = 0;
char* tmpBuf = chBuf;
do
{
fSuccess = ReadFile( hInputFile, tmpBuf, dwBytesToRead, &dwRead, NULL) ;
if (dwRead == 0)
break;
dwBytesToRead -= dwRead;
tmpBuf += dwRead;
}while(dwBytesToRead > 0);
fSuccess = WriteFile( hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL) ;
if ( !fSuccess )
return ;
if (! CloseHandle(hChildStdinWrDup))
ErrorExit("Close pipe failed/n");
CloseHandle ( hInputFile ) ;
}
void ReadFromPipe( LPTSTR lpOutputFile )
{
HANDLE hOutputFile = CreateFile( lpOutputFile, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOutputFile == INVALID_HANDLE_VALUE)
return ;
BOOL fSuccess ;
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE_] = { 0 };
if (!CloseHandle(hChildStdoutWr))
ErrorExit("Closing handle failed");
for (;;)
{
fSuccess = ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE_, &dwRead, NULL) ;
if( !fSuccess || dwRead == 0)
{
break;
}
fSuccess = WriteFile( hOutputFile, chBuf, dwRead, &dwWritten, NULL) ;
if ( !fSuccess )
break;
}
CloseHandle ( hOutputFile ) ;
}
void ErrorExit (LPTSTR lpszMessage)
{
MessageBox( 0, lpszMessage, 0, 0 );
}