vc进程间通信

进程通信4种方式

1.前面的剪贴板2.匿名管道3.命名管道4.油槽

匿名管道

父进程

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))//创建匿名管道 第1,2参数返回读和写的句柄,第三个指向一结构体见上面,第四个表明匿名管道使用默认的缓冲区大小
 {
  MessageBox("管道创建失败");
  return;
 }
 STARTUPINFO sui;
 PROCESS_INFORMATION pi;
 memset(&sui,0,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,TRUE,0,NULL,NULL,&sui,&pi))/*创建个启动子进程 第五个参数注意设为TRUE表示子进程可以继承父进程的所有句柄      第八个参数指定子进程的路径而且必须指定盘符 如果为NULL表明和父进程有同一个盘符和目录*/
 {
  CloseHandle(hRead);
  CloseHandle(hWrite);
  hRead=NULL;
  hWrite=NULL;
  MessageBox("子进程创建失败");
  return;
 }
 else
 {
  CloseHandle(pi.hProcess);  //记得关掉子进程的线程句柄
  CloseHandle(pi.hThread);   //记得关掉子进程的句柄  因为CreateProcess创建 + 打开了他们一次 所以因为他们是内核对象有使用计数 所以 应该如果不关此时计数是2
 }
}


 

//读取 和 写入 与子进程

void CParentView::OnPipeRead() 
{
 // TODO: Add your command handler code here
 char buf[100];
 DWORD ByteRead;
 if(!ReadFile(hRead,&buf,100,&ByteRead,NULL))
 {
  MessageBox("读取数据失败");
  return;
 }
 MessageBox(buf);
}

void CParentView::OnPipeWrite() 
{
 // TODO: Add your command handler code here
 char buf[]="父进程管道写入测试";
 DWORD ByteWrite;
 if (!WriteFile(hWrite,(LPVOID)buf,strlen(buf)+1,&ByteWrite,NULL))
 {
  MessageBox("写入数据失败");
  return;
 }
}


 

子进程

void CChildView::OnInitialUpdate() 
{
 CView::OnInitialUpdate();
 
 // TODO: Add your specialized code here and/or call the base class

//刚刚在父进程中 在一个sui的对象中将 子进程的 输入输出对象给了他们的 可以通过GetStdHandle取出来   可以通过这两个对象进行读和写  我这里就省略了.
 hRead=GetStdHandle(STD_INPUT_HANDLE);        

 hWrite=GetStdHandle(STD_OUTPUT_HANDLE);
}


 

命名管道

命名管道因为 可以跨网络的 所以分了服务端和客户端

服务端

//创建命名管道

void CNamedPipeSrvView::OnPipeCreate() 
{
 // TODO: Add your command handler code here

/*

这是创建命名管道的函数 第一个参数如果不是和本地的进程而是跨网络的 那.(点)后面应该是服务器的名称 pipe固定写法 MyPipe管道名称可自定义

第二个参数 指明双向访问方式和重叠操作

第三个参数 管道类型 0表明字节类型管道 读取方式也是字节类型读取 并且是等待方式 是一直等的也就是阻塞模式的

第四个参数 表明可以创建的实例最大数目数 我们设为了1

第五六个参数  表明 读取和写入的缓冲区大小吧 我们设为了1024字节

第七个参数 指定默认超时时间  我们指定为了0 同一管道不同实例 也必须这个值

第八个参数 安全性NULL 默认的安全性   

*/
 hPipe=CreateNamedPipe("\\\\.\\pipe\\MyPipe",PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL);
 if (INVALID_HANDLE_VALUE==hPipe)
 {
  MessageBox("命名管道创建失败!");
  hPipe=NULL;
  return;
 }

//因为是重叠操作滴 所以ConnectNamedPipe等待连接操作之前 必须创建一个人工事件对象 
 HANDLE hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
 if (!hEvent)
 {
  MessageBox("事件对象创建失败!");
  return;
 }
 OVERLAPPED ovlp;

//用此函数现将结构体其余部分设为0 避免函数操作
 memset(&ovlp,0,sizeof(OVERLAPPED));

//指定事件对象
 ovlp.hEvent=hEvent;

//等待客户端的请求 连接 ,这个操作如果成功执行完后 刚刚的人工事件对象 会成为有信号的状态.
 if(!ConnectNamedPipe(hPipe,&ovlp))
 {
  if (ERROR_IO_PENDING!=GetLastError())
  {
   MessageBox("管道等待连接失败!");
   CloseHandle(hPipe);
   hPipe=NULL;
   CloseHandle(hEvent);
   return;
  }
 }

//等待获取人工事件对象.
 if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE))
 {
  MessageBox("等待对象失败!");
  CloseHandle(hEvent);
  CloseHandle(hPipe);
  hPipe=NULL;
  return;
 }
 CloseHandle(hEvent);
}


 

//读和写 部分的编写

//读

void CNamedPipeSrvView::OnPipeRecv() 
{
 // TODO: Add your command handler code here
 char recvBuf[100];
 DWORD recvCz;
 if(!ReadFile(hPipe,recvBuf,100,&recvCz,NULL))  //想不通一点 孙鑫说 重叠操作 读取数据这里操作没完成也可以立即返回 ,完成后系统会通知,没完成这里返回的什么值?
 {
  MessageBox("读取数据失败!");
  return;
 }
 MessageBox(recvBuf);
}


 

//写

void CNamedPipeSrvView::OnPipeSend() 
{
 // TODO: Add your command handler code here
 DWORD sendCz;
 if (!WriteFile(hPipe,"服务端命名管道写入测试",strlen("服务端命名管道写入测试")+1,&sendCz,NULL))
 {
  MessageBox("写入数据失败!");
  return;
 }
}


 

客户端

//等待可用管道 与打开

void CNamedPipeCltView::OnPipeConnet() 
{
 // TODO: Add your command handler code here

//等待可用的管道  第一个参数上面说了不解释 第二个参数让他一直等待
 if(!WaitNamedPipe("\\\\.\\pipe\\Mypipe",NMPWAIT_WAIT_FOREVER))
 {
  MessageBox("等待可用管道失败!");
  return;
 }

/*

打开可用管道 第一个参数 不解释

第二个参数 表明你打开了是读还是写

第三个参数 表明共享 不共享则为0

第四个参数 默认安全性

第五个参数 表明打开现已存在的

第六个参数 属性 为默认不同

第七个参数 模板为空

*/
 hPipe=CreateFile("\\\\.\\pipe\\Mypipe",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if (INVALID_HANDLE_VALUE==hPipe)
 {
  MessageBox("打开管道失败!");
  CloseHandle(hPipe);
  hPipe=NULL;
  return;
 }
}
//得到命名管道的句柄后 就可以利用 WriteFile 和ReadFile 和服务端进程进行读和写了 这里省略不写

 

油槽

油槽也是基于网络的 所以油槽也分服务端和客户端  并且是广播式的 可以一对多 不过他对传输的数据大小有限制 不能大于420字节

服务端只能接受数据 客户端发送,  当然如果想要在一个程序中同时有接受和发送的功能 ,你可以把客户端的发送代码集成到服务端中.

服务端

void CMailSlotView::OnMailslotRecv() 
{
 // TODO: Add your command handler code here

/*

创建油槽 第一个参数写法见命名管道的那个就懂了

第二个参数 指定写入到油槽消息的大小  我们让其可以发送任意大小 所以设为0

第三个参数 等待超时值 为0没有消息则立刻返回 大于0的话呢在超时之前可以等待知道消息来到或超时结束 我们让其一直等待知道有消息可用

第四个参数 默认安全性NULL
 hMailslot=CreateMailslot("\\\\.\\mailslot\\Mymailslot",0,MAILSLOT_WAIT_FOREVER,NULL);
 if (INVALID_HANDLE_VALUE==hMailslot)
 {
  printf("油槽创建失败");
  hMailslot=NULL;
  return;
 }
 char recvBuf[100];
 DWORD recvCz;

//读取数据
 if(!ReadFile(hMailslot,recvBuf,100,&recvCz,NULL))
 {
  MessageBox("读取数据失败!");
  return;
 }
 MessageBox(recvBuf);
 CloseHandle(hMailslot);
}


客户端


 

void CMailSlotCltView::OnMailslotSend() 
{
 // TODO: Add your command handler code here

//打开油槽 第三个参数指定为共享可读 说是服务器那边要读 想不通为何命名管道那不用 就当硬性规定吧
 hMailSlot=CreateFile("\\\\.\\mailslot\\Mymailslot",GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if (INVALID_HANDLE_VALUE==hMailSlot)
 {
  hMailSlot=NULL;
  MessageBox("打开油槽失败!");
  return;
 }
 DWORD sendCz;

//写 发送数据
 if (!WriteFile(hMailSlot,"客户端命名管道写入测试",strlen("客户端命名管道写入测试")+1,&sendCz,NULL))
 {
  MessageBox("写入数据失败!");
  return;
 }
  CloseHandle(hMailSlot);

}


 

总结

1.匿名管道 :只能在本地进程间进行通信 并且只能是父子进程间通信 子进程必须由父进程创建才能通信 完成句柄的继承

2.命名管道 :基于网络的分了服务器和客户端来进行通信

3.油槽          :基于网络的广播式的 对传输数据大小有限制 420字节左右

4.剪贴板      :不解释

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值