利用匿名管道在父子进程间传递数据

利用匿名管道在父子进程间传递数据

进程间传递数据有很多种方法,常用到的有命令行、共享内存、内存映射文件、剪贴板、windows消息、socket等。

命令行的缺点是数据长度限制。Windows2000只能传递256个字节,内存映射文件、共享内存都需要一些进程同步才能很好的配合读写数据,剪贴板可能会被其他进程擦数数据。当多开的时候很难控制进程间的对应关系。

一种解决方案是生成随机命名的同步控制对象,然后利用命令行传递名字。同步控制对象可以通过唯一的名字再另一个进程中获取其引用。

相对来说用同步对象会稍有些麻烦,匿名管道可以很好的解决这些问题。子进程可以继承父进程中创建的句柄,父子进程一一对应的关系不会被打乱。而且使用简单,父子进程可以双向通信。

 

用法:

1.       首先创建两条匿名管道,一条用于发送数据给子进程,一条用于从子进程接收数据,安全描述符中指定可继承性 saAttr.bInheritHandle = TRUE;

2.       每条匿名管道包括两个句柄,一个读一个写,可以理解为管道的两端,从写端写出的数据可以从读端读取。所以父进程需要一条管道来接收数据,一条发送数据。

3.       windowsIO操作都可以用WriteFile ReadFile来完成,默认模式下数据发送和接收是阻塞的,管道的数据发送与接收也可以用重叠模式来进行。

4.       CreateProcess子进程时参数.bInheritHandle需要传真,保证句柄的可继承性。

5.       利用STARTUPINFO传递管道端口给子进程,父窗口发送数据的管道的读端口,和父窗口等待接收数据的管道的写端口,利用STDHANDLES来传递。

 

 STARTUPINFO  starinfo ={0};

    starinfo.cb 
= sizeof(starinfo);       

    starinfo.hStdInput 
= hSendReadPipe;

    starinfo.hStdOutput
= hRecvWritePipe;

    starinfo.hStdError 
= hRecvWritePipe;

    starinfo.dwFlags 
|= STARTF_USESTDHANDLES;

 

 

6.       子进程从STDHANDLES获得两个句柄用来读写。

 

HANDLE hRead  = GetStdHandle(STD_INPUT_HANDLE);   

HANDLE hWrite 
= GetStdHandle(STD_OUTPUT_HANDLE);

 

 

 

下面是完整代码:

 

 



BOOL CreatePipe()

{

       SECURITY_ATTRIBUTES saAttr; 

       saAttr.nLength 
= sizeof(SECURITY_ATTRIBUTES); 

       saAttr.bInheritHandle 
= TRUE; 

       saAttr.lpSecurityDescriptor 
= NULL; 

       
/*'创建匿名管道*/

       
if (!CreatePipe(&hSendReadPipe,&hSendWritePipe, &saAttr, 0))

       
{

              ::LogMsg(
"CreatePipe failed!");

              
return FALSE;

       }


       
/*'构造写句柄的复制体*/

       
if(!DuplicateHandle(GetCurrentProcess(), hSendWritePipe, 

              GetCurrentProcess(), 
&hSendWritePipeDup, 0,FALSE,DUPLICATE_SAME_ACCESS))

       
{

              ::LogMsg(
"DuplicateHandle Handle!");

              
return FALSE;

       }


       CloseHandle(hSendWritePipe);

 

       
//////////////////////////////////////////////////////////////////////////

       
if (!CreatePipe(&hRecvReadPipe,&hRecvWritePipe, &saAttr, 0))

       
{

              ::LogMsg(
"CreatePipe failed!");

              
return FALSE;

       }


       
/*'构造写句柄的复制体*/

       
if(!DuplicateHandle(GetCurrentProcess(), hRecvReadPipe, 

              GetCurrentProcess(), 
&hRecvReadPipeDup, 0,FALSE,DUPLICATE_SAME_ACCESS))

       
{

              ::LogMsg(
"DuplicateHandle Handle!");

              
return FALSE;

       }


       CloseHandle(hRecvReadPipe);

       
return TRUE;

}


 

 

 

 

BOOL ReadFromPipe()

{

       DWORD dwReaded 
=0;

       
char szBuf[255];

       
return ReadFile(hRecvReadPipeDup, szBuf, sizeof(szBuf), &dwReaded, NULL);     ;

}


 

void WaitForReply()

{

       
while ( !ReadFromPipe()){}

}


 

BOOL WriteToPipe()

{

       
char szData[1024];

       
int nSize = sizeof(g_cmdData);

       CompressData((
char*)&g_cmdData,nSize,szData);

       

       
/*'对管道进行写操作*/

       DWORD dwWrited 
=0;

       BOOL bSuccess 
= TRUE;

       bSuccess 
&= WriteFile(hSendWritePipeDup, (LPCVOID)szData, nSize, &dwWrited, NULL);

 

       CloseHandle(hSendWritePipeDup);      

       
if ( !bSuccess )

       
{

              ::LogMsg(
"WriteFile failed!");                           

              
return FALSE;

       }
     

       
return TRUE;

}


 

BOOL CreateGameProcess()

{

       
char strDir[MAX_PATH] ={0};

       
char strPath[MAX_PATH]={0};

 

       GetCurrentDirectory(MAX_PATH,strDir);

       strcpy(strPath,strDir);    

 

#ifdef _DEBUG

       const 
char* pszFileName = "\\main_debug.exe";

#
else

       const 
char* pszFileName = "\\main.exe";

#endif

       strcat(strPath,pszFileName);

 

       
if ( !CreatePipe() )

       
{     

              ::LogMsg(
"CreatePipe failed!");

              
return FALSE;

       }


 

       STARTUPINFO  starinfo 
={0};

       starinfo.cb 
= sizeof(starinfo);       

    starinfo.hStdInput 
= hSendReadPipe;

       starinfo.hStdOutput
= hRecvWritePipe;

       starinfo.hStdError 
= hRecvWritePipe;

    starinfo.dwFlags 
|= STARTF_USESTDHANDLES;

 

    PROCESS_INFORMATION processinfo 
={0};

       

       BOOL bRet 
=::CreateProcess(strPath, " fromlogin", NULL,NULL,TRUE,NULL,NULL,strDir,&starinfo,&processinfo);

       
if(bRet)

       
{

//            WaitForInputIdle(processinfo.hProcess,INFINITE);

              dwGameProcessID 
= processinfo.dwProcessId;

              CloseHandle(processinfo.hProcess);

              CloseHandle(processinfo.hThread);

              
return TRUE;

       }


       ::LogMsg(
"CreateProcess failed!");

 

       

       
return FALSE;

}


 

 

子进程中接收数据:

 



       DWORD dwReaded 
=0;                      

       HANDLE hRead  
= GetStdHandle(STD_INPUT_HANDLE); 

       HANDLE hWrite 
= GetStdHandle(STD_OUTPUT_HANDLE);

       

       
if( hRead )

       
{                   

              
/*'从管道接收数据*/

              const 
int  nBufSize = 2048;

              
char        szBuf[nBufSize];

              
if(ReadFile(hRead, &szBuf,nBufSize, &dwReaded, NULL))

              
{

}


}

posted on 2007-05-11 00:24 修一居士 阅读(7734) 评论(4)  编辑 收藏 引用

评论

# re: 利用匿名管道在父子进程间传递数据[未登录] 2007-05-11 11:11 梦在天涯

不错,有机会也用一把
!  回复  更多评论   

# 很感兴趣,但是有个地方没有看懂,lz可以解释一下么,谢谢了 2007-05-26 07:50 icewind

很感兴趣,但是有个地方没有看懂,lz可以解释一下么,谢谢了
BOOL bRet =::CreateProcess(strPath, " fromlogin",
NULL,NULL,TRUE,NULL,NULL,strDir,&starinfo,&processinfo);

if(bRet)

{

// WaitForInputIdle(processinfo.hProcess,INFINITE);

/*不明白为什么要关闭句柄
dwGameProcessID = processinfo.dwProcessId;

CloseHandle(processinfo.hProcess);

CloseHandle(processinfo.hThread);
*/
return TRUE;

}
  回复  更多评论   

# re: 利用匿名管道在父子进程间传递数据 2007-05-31 14:04 南斗

windows 核心编程里有详细的解释,你创建得到的进(线)程句柄你关闭它是说你不想在使用这个句柄了,并不表示关闭就是摧毁,进(线)程句柄自己会维持一个引用计数,当它结束的时候引用计数会减一。  回复  更多评论   

# re: 利用匿名管道在父子进程间传递数据[未登录] 2013-09-11 14:16 riverqh

看不懂为什么在CreatePipe之后要DuplicateHandle然后CloseHandle原来由CreatePipe创建的通道。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

统计

常用链接

留言簿(3)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜