匿名管道--进程间的通信

211 篇文章 3 订阅

匿名管道

匿名管道是一种未命名的、单向管道,通常用来在一个父进程和一个子进程之间传输数据。匿名的管道只能实现本地机器上两个进程间的通信,而不能实现跨网络的通信。

1.1匿名管道
    匿名管道是一种未命名的、单向管道。通常用来在父进程和子进程之间传输数据。匿名管道总是本地的,不能在网络之间传递数据。
1.1.1匿名管道操作
    CreatePipe函数创建一个匿名管道,并且返回两个句柄:一个读管道的句柄和一个写管道的句柄。读句柄具有管道的只读权限,写句柄具有管道的只写权限。为了利用管道交换数据,管道服务端必须把管道句柄传给另一个进程。通常情况下,这是通过继承实现的(参见1.1.2);就是说,父进程允许子进程继承这个句柄。进程也可以使用DuplicateHandle函数复制一个管道句柄,再通过一些进程间通信机制,比如DDE或者共享内存,把它发送给另一个不相关的进程。
    管道服务端可以给管道服务端发送读句柄或者写句柄,这取决于客户端要用这个管道发送数据还是获取数据。要从管道读取数据,以管道的读句柄为参数调用ReadFile函数。当另一个进程向管道写入数据是,ReadFile函数返回。如果管道的所有写句柄被关闭,或者读取数据时有错误发生,ReadFile函数也会返回。
    要向管道写入数据,以管道的写句柄问参数,调用WriteFile函数。数据被完全写入管道,或者出错,WriteFile将会返回。如果管道的缓存已满,且还有尚未写完的数据,直到另一个进程从管道读取数据前,WriteFile函数都不会返回。缓存的大小是在管道服务端调用CreatePipe函数时指定的。
    匿名管道不支持异步读写。这意味着不能使用ReadFileEx和WriteFileEx函数读写匿名管道。另外,使用匿名管道时,ReadFile和WriteFile函数的lpOverlapped参数也会被忽略。
    匿名管道会一直存在,直到所有的读写句柄全部被关闭。进程可以调用CloseHandle函数关闭管道句柄。进程终止时,所有的管道句柄也会被自动关闭。
1.1.2管道句柄的继承
    通过一下几个方法,管道服务端控制管道句柄是否可以被继承:
    一、调用CreatePipe时,将SECURITY_ATTRIBUTES参数的成员bInheritHandle设为TRUE,那么这个CreatePipe创建的管道就可以被继承。
    二、管道服务端可以利用DuplicateHandle函数改变管道句柄的继承特性。管道服务到可以从可继承的管道句柄复制出不可继承的句柄,也可以从不可继承的管道句柄复制出可继承的句柄。
    三、CreateProcess函数使得管道服务端可以决定子进程是否继承自己的所有句柄。

在同一个目录下面建立两个不同的工程Parent和Child:

·@父进程的实现

1.添加两个私有成员变量

    // Attributes

private:

       HANDLE hWrite;

       HANDLE hRead;

初始化为NULL

CParentView::CParentView()

{

         // TODO: add construction code here

         hWrite = NULL;

         hRead = NULL;

}

在析构函数中关闭这两个变量。

CParentView::~CParentView()

{

  if(hRead)

         CloseHandle(hRead);

  if(hWrite)

         CloseHandle(hWrite);

}

2.匿名管道的创建

void CParentView::OnPipeCreate()

{

       // TODO: Add your command handler code here

       SECURITY_ATTRIBUTES sa;

       sa.bInheritHandle = TRUE;

       sa.lpSecurityDescriptor = NULL;

       sa.nLength = sizeof(SECURITY_ATTRIBUTES);

       if(!CreatePipe(&hRead,&hWrite,&sa,0))

       {

              MessageBox("创建匿名管道失败!");

              return;

       }

 

       STARTUPINFO sui;

       PROCESS_INFORMATION pi;

       ZeroMemory(&sui,sizeof(STARTUPINFO));

       sui.cb = sizeof(STARTUPINFO);

       sui.dwFlags = STARTF_USESTDHANDLES;

       sui.hStdInput = hRead;

       sui.hStdOutput = hWrite;

       sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);

 

       //if(!CreateProcess("..//Child//Debug//Child.exe",NULL,NULL,NULL,

       if(!CreateProcess("..//Parent//Debug//Child.exe",NULL,NULL,NULL,

              TRUE,0,NULL,NULL,&sui,&pi))

       {

              CloseHandle(hRead);

              CloseHandle(hWrite);

              hRead = NULL;

              hWrite = NULL;

              MessageBox("创建子进程失败!");

              return;

       }

       else

       {

              CloseHandle(pi.hProcess);

              CloseHandle(pi.hThread);

       }

}

3.匿名管道的读取操作

void CParentView::OnPipeRead()

{

       // TODO: Add your command handler code here

       char buf[100];

       DWORD dwRead;

       if(!ReadFile(hRead,buf,100,&dwRead,NULL))

       {

              MessageBox("读取数据失败!");

              return ;

       }

       MessageBox(buf);

}

4.匿名管道的写入操作

void CParentView::OnPipeWrite()

{

       // TODO: Add your command handler code here

       char buf[] = "http://www.sina.com.cn";

       DWORD dwWrite;

       if(!WriteFile(hWrite,buf,strlen(buf) + 1,&dwWrite,NULL))

       {

              MessageBox("写入数据失败!");

              return ;

       }

}

 

·@子进程的实现

1. // Attributes

private:

       HANDLE hWrite;

       HANDLE hRead;

CChildView::CChildView()

{

       // TODO: add construction code here

       hRead = NULL;

       hWrite = NULL;

}

 

 

CChildView::~CChildView()

{

       if(hRead)

              CloseHandle(hRead);

       if(hWrite)

              CloseHandle(hWrite);

}

 

2.获取管道的读取和写入句柄

void CChildView::OnInitialUpdate()

{

       CView::OnInitialUpdate();

      

       // TODO: Add your specialized code here and/or call the base class

       hRead = GetStdHandle(STD_INPUT_HANDLE);

       hWrite = GetStdHandle(STD_OUTPUT_HANDLE);

}

3.读取数据

void CChildView::OnPipeRead()

{

       // TODO: Add your command handler code here

       char buf[100];

       DWORD dwRead;

       if(!ReadFile(hRead,buf,100,&dwRead,NULL))

       {

              MessageBox("读取数据失败!");

              return ;

       }

       MessageBox(buf);

}

4.写入数据

void CChildView::OnPipeWrite()

{

       // TODO: Add your command handler code here

       char buf[] = "匿名管道测试程序";

       DWORD dwWrite;

       if(!WriteFile(hWrite,buf,strlen(buf) + 1,&dwWrite,NULL))

       {

              MessageBox("写入数据失败!");

              return ;

       }

}

利用匿名管道实现父子进程间通信时,需要注意一点:因为匿名管道没有名称,所以只能在父进程中调用CreateProcess函数创建子进程时,将管道的读、写句柄传递给子进程。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值