8、进程通信-匿名管道
匿名管道
一个单向,未命名的管道,通常用来在一个父进程和一个子进程间传输数据。只能实现本地机器上两个进程间的通信,而不能实现跨网络的通信。
BOOL CreatePipe(
PHANDLE hReadPipe, // read handle
PHANDLE hWritePipe, // write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // security attributes
DWORD nSize // pipe size
);
CreateProcess 创建进程
创建父进程:
a. CreatePipe:其中第三个参数代表安全属性结构体SECURITY_ATTRIBUTES的指针,在前几章的运用中,都是运用了NULL,代表返回的安全句柄不可以被子进程所继承。但在本运用中,涉及到的是匿名管道。匿名管道就是父子进程之间的通信,所以结构体必须设置相应的值。子进程要想获得匿名管道的读写句柄,只能从父进程继承而来。一旦子进程有了继承而来的读写句柄,就可以和父进程进行通信了。对于机构体SECURITY_ATTRIBUTES,最重要的是第三个参数bInheritHandle,表示Specifies whether the returned handle is inherited when a new process is created. If this member is TRUE, the new process inherits the handle.
b. CreateProcess:如果创建管道成功,则创建子进程,并将管道的读写句柄传递给子进程。
1.MFC单文档程序菜单中增加创建管道,读取数据,写入数据三项
2.View类中增加成员变量
3. CreateProcess
倒数第三个参数 [in] Pointer to a STARTUPINFO structure that specifies how the main window for the new process should appear 指向STARTUPINFO结构体的一个指针,用来指定新的进程它的主窗口如何出现
最后一个参数指向PROCESS_INFORMATION结构体的一个指针的返回值,用来接收新的进程的标识信息
PROCESS_INFORMATION
The PROCESS_INFORMATION structure is filled in by the CreateProcess function with information
about a newly created process and its primary thread.
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
Members
hProcess //新创建进程的句柄
A handle to the newly created process. The handle is used to specify the process in all
functions that perform operations on the process object.
hThread //新创建进程主线程的句柄
A handle to the primary thread of the newly created process. The handle is used to specify
the thread in all functions that perform operations on the thread object.
dwProcessId //全局进程标识符,如果进程结束操作系统可能会将标识分配给其他进程,我们调用标识的时候要确保进程在运行
A global process identifier that can be used to identify a process. The value is valid from the time the process is created until the time the process is terminated.
dwThreadId //全局线程标识符
A global thread identifiers that can be used to identify a thread. The value is valid from the
time the thread is created until the time the thread is terminated.
创建匿名管道具体代码:
SECURITY_ATTRIBUTES sa;
//总共就三个参数
sa.bInheritHandle=TRUE; //表示可被子进程所继承
sa.lpSecurityDescriptor=NULL; //安全描述符号一般都设置成NULL,即默认描述符
sa.nLength=sizeof(SECURITY_ATTRIBUTES); //管道长度
if(!CreatePipe(&hRead,&hWrite,&sa,0))
{
MessageBox("创建匿名函数失败!");
return;
}
//管道创建成功后,接着创建子进程,并将读写句柄传递给子进程
STARTUPINFO sui;
PROCESS_INFORMATION pi;
//调用ZeroMemory方法将该结构体中的所有成员都置为0,这是因为这个结构体的成员很多,如果开始的时候没有置为0的话,那它的值是随机的,将这样的结构体传给CreateProcess,可能会影响到执行的结果。
ZeroMemory(&sui,sizeof(STARTUPINFO));
sui.cb=sizeof(STARTUPINFO); //设置结构体的大小
sui.dwFlags=STARTF_USESTDHANDLES; //该标识表示标准输入句柄,标准输出句柄和错误句柄是有用的
sui.hStdInput=hRead; //将子进程的输入句柄设置成父进程的读句柄
sui.hStdOutput=hWrite; //将子进程的输出句柄设置成父进程的写句柄
sui.hStdError=GetStdHandle(STD_ERROR_HANDLE); //得到标准错误句柄,是父进程的错误句柄,该行代码在本程序中没有实际的用途意义
//因为是匿名管道,是没有名称的管道,只有通过CreateProcess由上而下的传递管道操作句柄。
if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,
TRUE,0,NULL,NULL,&sui,π))
{
MessageBox("创建子进程失败!");
CloseHandle(hRead);
CloseHandle(hWrite);
//避免在析构函数中再次关闭,析构函数采用:
//if(hRead) CloseHandle(hRead)
hRead=NULL;
hWrite=NULL;
return;
}
else
{
//创建一个新的进程的时候,系统会创建一个进程内核对象和一个线程内核对象,内核对象都有一个使用基数,初始调用的时候,都设置为1。在CreateProcess返回之前,该函数打开进程和线程的内核对象,并将进程相关的句柄放置到结构体PROCESS_INFORMATION的hProcess和hThread中,当Process在内部打开这些对象的时候,使得每个对象的使用基数增加到2了。如果在父进程中不需要使用这两个句柄,就将这个句柄进行关闭,使得使用基数减1。当子进程终结的时候,系统会在将使用基数减1,使得子进程的进程内核对象和线程内核对象的使用基数变为0,这样内核对象就可以被释放了。
CloseHandle(pi.hProcess); //关闭子进程的句柄
CloseHandle(pi.hThread); //关闭子进程中主线程的句柄
}
父进程写匿名管道:
char *buf="hello world";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("匿名管道写入数据失败!");
return;
}
父进程读匿名管道:
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("匿名管道读取数据失败!");
return;
}
MessageBox(buf);
创建子进程程序:
可以将获取父进程的匿名管道的读写句柄操作放在CView类的OnInitialUpdate方法中实现,该方法是在CView完全构造后调用的第一个方法。代码如下:
hRead=GetStdHandle(STD_INPUT_HANDLE);
hWrite=GetStdHandle(STD_OUTPUT_HANDLE);
子进程的读写匿名管道的代码和父进程的一样,这里不再累述。
为了让子进程从众多继承的句柄中区分出管道的读、写句柄,就必须将子进程的特殊句柄设置为管道的读写句柄。
参考
[1]MSDN
[2]《VC++ 深入》
[3]http://blog.csdn.net/liufei_learning/archive/2009/12/17/5026410.aspx