zoukankan      html  css  js  c++  java
  • vc++17 进程间的通信

    进程间的通信模式:

    ①、剪贴板

    建立一个APPWIZARD,然后创建2个按钮(发送,接收),2个编辑框,

    对按钮添加函数;

    void CClickDlg::OnButtonSend() 
    {
    	//打开剪贴板,保存信息于剪贴板上
    
    	if(OpenClipboard())
    	{
    		CString str;
    		HANDLE hClip;
    		char *pbuf;//
    		EmptyClipboard();
    		GetDlgItemText(IDC_EDIT_SEND,str);
    
    		hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//分配一个内存对象
    		//对一个内存对象加锁,并返回其地址;
    		pbuf=(char*)GlobalLock(hClip);
    		strcpy(pbuf,str);
    		GlobalUnlock(hClip);
    		//设置剪贴板的数据
    		SetClipboardData(CF_TEXT,hClip);//参数格式
    		CloseClipboard();
    	}
    }
    
    void CClickDlg::OnButtonRecv() 
    {
    	OpenClipboard();
    	if (IsClipboardFormatAvailable(CF_TEXT))
    	{
    		HANDLE hclip;
    		char *pbuf;
    
    		hclip=GetClipboardData(CF_TEXT);//得到剪贴板的消息
    		pbuf=(char*)GlobalLock(hclip);//对欲加锁消息加锁
    		GlobalUnlock(hclip);
    		SetDlgItemText(IDC_EDIT_RECV,pbuf);
    		CloseClipboard();
    	}
    
    }
    

    ②,通过管道同步消息

    创建匿名管道:

    1建立单文档appwizard之pipe,添加三个菜单,“创建匿名管道,读取data,写入data”

    2添加句柄hread hwrite,

    3添加相应菜单“创建匿名管道”的菜单函数

    void CPipeView::OnPipeCreate() 
    {
    	SECURITY_ATTRIBUTES sa;
    	sa.bInheritHandle=TRUE;
    	sa.lpSecurityDescriptor=NULL;
    	sa.nLength=sizeof(SECURITY_ATTRIBUTES);
    	if(!CreatePipe(&hRead,&hWrite,&sa,0))
    	{
    		MessageBox("创建匿名管道失败");
    		return ;
    	}
    	//启动子进程,交给读写选项;
    	STARTUPINFO stinfo;
    //	memset(&stinfo,0,sizeof(STARTUPINFO));
    	ZeroMemory(&stinfo,sizeof(STARTUPINFO));
    //对所用到的结构成员赋值
    	stinfo.cb=sizeof(STARTUPINFO);
    	stinfo.dwFlags=STARTF_USESTDHANDLES;//结构体,标准输入\出句柄有效
    	stinfo.hStdInput=hRead;
    	stinfo.hStdOutput=hWrite;//将进程的标准入\出句柄设置为管道的读写句柄
    	stinfo.hStdError=GetStdHandle(STD_ERROR_HANDLE);//获得父进程的标准错误句柄;
    	
    	
    	//进程消息的指针LPPROCESS_INFORMATION定义
    	PROCESS_INFORMATION pl;
    
    	if(!CreateProcess("E:\\vc6.0\\MSDev98\\MyProjects\\test\\child\\child\\Debug\\child.exe",NULL,NULL,NULL,TRUE,0,NULL,NULL,&stinfo,&pl))//创建一个子线程,实现通过管道进行子进程和父进程的通信;
    	{
    		CloseHandle(hRead);
    		CloseHandle(hWrite);
    		hRead=NULL;
    		hWrite=NULL;
    		MessageBox("创建子进程失败");
    		return;
    	}
    	else
    	{
    		CloseHandle(pl.hProcess);//将内核对象计数器减 1,为0是收回你内核对象的内存
    		CloseHandle(pl.hThread);
    	}
    }

    重要的是两个函数,一个是Createpipe()和另一个CreateProecess()函数;

    3、添加“读取数据”函数响应

    void CPipeView::OnPipeRead() 
    {
    	char buf[100]={0};
    	DWORD dwRead;//保存实际读取的字节数;
    	if(!ReadFile(hRead,buf,100,&dwRead,NULL))
    	{
    		MessageBox("读取失败");
    			return;
    
    	}
    	MessageBox(buf);
    
    }

    4 添加“读取数据”函数响应

    void CPipeView::OnPipeWrite() 
    {
    	char buf[]="this is my test pipe";
    	DWORD dwWrite;
    	if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
    	{
    		MessageBox("写入失败");
    		return;
    	}
    }

    5编写关于 子进程Child的实现,同样的创建一个appwizard 单文档,命名为“child”,然后添加菜单,“接收data”和“发送data”

    6.添加句柄 hread和hwrite 以保存表示输入和输出句柄;

    7添加关于View类里面的onnitialUpdate的虚函数,并在这个里面获得标准输入\出句柄;

    void CChildView::OnInitialUpdate() 
    {
    	CView::OnInitialUpdate();
    	//获得标准的读写句柄
    	hRead=GetStdHandle(STD_INPUT_HANDLE);
    	hWrite=GetStdHandle(STD_OUTPUT_HANDLE);
    	
    }
    


    8添加Child的菜单的“接收data”和“发送Data”的函数

    void CChildView::OnPipeWrite() 
    {
    	
    	char buf[]="匿名管道测试";
    	DWORD dwWrite;
    	if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))//WriteFile()读写管道
    	{
    		MessageBox("写入失败");
    		return;
    	}
    }
    
    void CChildView::OnPipeRead() 
    {
    	char buf[100]={0};
    	DWORD dwRead;//保存实际读取的字节数;
    	if(!ReadFile(hRead,buf,100,&dwRead,NULL))//ReadFile,读管道消息
    	{
    		MessageBox("读取失败");
    		return;
    		
    	}
    	MessageBox(buf);	
    	
    }




    运行父进程“创建匿名管道”,启动子进程,便可以进行进程之间的通信;

    利用命名管道

    匿名管道只能在父子子进程进行通信,而.命名管道:还可以跨网络通信,服务器只能在win2000NT下运行!而客户端可以在95下运行。关键函数CreateNamedPipe

     

    创建一个基于命名管道的进程通信例子

    服务器端部分

    1.添加一个句柄变量来保存一个命名管道的实例句柄(View类里面)

    2.添加“创建命名管道的响应函数”

    //创建一个句柄变量来保存一个命名管道的实例句柄
    void CNamedPipeView::OnPipreCreate() 
    {
    	
    	hPipe=CreateNamedPipe("\\\\.\\pipe\\mypipe",PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL);
    	if (INVALID_HANDLE_VALUE==hPipe)
    	{
    		MessageBox("创建命名管道失败");
    		return;
    	}
    	HANDLE hEvent;
    	hEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
    	if (!hEvent)
    	{
    		MessageBox("创建时间失败");
    		return;
    	}
    	OVERLAPPED owlap;
    	memset(&owlap,0,sizeof(owlap));
    	owlap.hEvent=hEvent;
    	if(!ConnectNamedPipe(hPipe,&owlap))
    	{
    		if (ERROR_IO_PENDING!=GetLastError())//此处返回值如果是ERROR_IO_PENDING不表示错误,而是稍后可能继续执行
    		{
    
    			MessageBox("等待客户端连接失败!");
    			CloseHandle(hPipe);
    			CloseHandle(hEvent);
    			hPipe=NULL;
    			return;
    		}
    		if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE))
    		{
    			MessageBox("等待对象失败");
    			return;
    		}
    		CloseHandle(hEvent);
    
    	}
    }

    3,添加发送和接收部分的函数

    void CNamedPipeView::OnEditWrite() 
    {
    	// TODO: Add your command handler code here
    	char buf[]="服务器端写入:匿名管道测试";
    	DWORD dwWrite;
    	if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))//WriteFile()读写管道
    	{
    		MessageBox("服务器端写入失败");
    		return;
    	}
    }
    
    void CNamedPipeView::OnEditRead() 
    {
    	char buf[100]={0};
    	DWORD dwRead;//保存实际读取的字节数;
    	if(!ReadFile(hPipe,buf,100,&dwRead,NULL))//ReadFile,读管道消息
    	{
    		MessageBox("服务器端读取失败");
    		return;
    		
    	}
    	MessageBox(buf);
    	
    }

    客户端部分的程序:

    1,同服务器端部分的第一二部分

    2.建立“连接管道的函数”

    void CNamedPipeCotView::OnPipeConnect() 
    {
    	// TODO: Add your command handler code here
    	if(!WaitNamedPipe("\\\\.\\pipe\\mypipe",NMPWAIT_WAIT_FOREVER))
    	{
    		MessageBox("当前没有课命名的管道实例");
    		return;
    	}
    	hpipe=CreateFile("\\\\.\\pipe\\mypipe",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);//可以对文件操作,也可以对管道操作;
    	if (hpipe==INVALID_HANDLE_VALUE)
    	{
    		MessageBox("打开命名管道失败");
    		hpipe=NULL;
    		return;
    	}
    
    }

    3,建立接收和发送的函数

    void CNamedPipeCotView::OnPipeRead() 
    {
    	char buf[100]={0};
    	DWORD dwRead;//保存实际读取的字节数;
    	if(!ReadFile(hpipe,buf,100,&dwRead,NULL))//ReadFile,读管道消息
    	{
    		MessageBox("客户端读取失败");
    		return;
    		
    	}
    	MessageBox(buf);
    }
    
    void CNamedPipeCotView::OnPipeWrite() 
    {
    	char buf[]="客户端写入:匿名管道测试";
    	DWORD dwWrite;
    	if(!WriteFile(hpipe,buf,strlen(buf)+1,&dwWrite,NULL))//WriteFile()读写管道
    	{
    		MessageBox("客户端写入失败");
    		return;
    	}
    	   
    }


    四、通过邮槽来实现进程间通信;

    邮槽是一种单向传送机制;邮槽是基于广播的,可以一对多发送。但只能一个发送,一个接收,要想同时发送接收,须写两次代码。

    服务器端部分:创建邮槽,准备接收数据

    void CMailSlotSrvView::OnMailslotRecv() 
    {
    	HANDLE HMailSlot;
    	HMailSlot=CreateMailslot("\\\\.\\mailslot\\MyMailSlot",0,MAILSLOT_WAIT_FOREVER,NULL);
    	if (INVALID_HANDLE_VALUE==HMailSlot)
    	{
    		MessageBox("创建油槽失败");
    		HMailSlot=NULL;
    		return;
    	}
    //创建成功,接收数据,因为服务器端只能接收数据;
    	char buf[100]={0};
    	DWORD dwRead;//保存实际读取的字节数;
    	if(!ReadFile(HMailSlot,buf,100,&dwRead,NULL))//ReadFile,读管道消息
    	{
    		MessageBox("客户端读取失败");
    		CloseHandle(HMailSlot);
    		return;
    		
    	}
    	MessageBox(buf);
    	CloseHandle(HMailSlot);
    }
    



    建立客户端发送数据部分:

    void CMailSlotClientView::OnMailslotSend() 
    {
    	HANDLE  hMailSlotClient;
    	hMailSlotClient=CreateFile("\\\\.\\mailslot\\MyMailSlot",GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);//打开油槽;
    	if (INVALID_HANDLE_VALUE==hMailSlotClient)
    	{
    		MessageBox("打开油槽失败");
    		hMailSlotClient=NULL;
    		return;
    
    	}
    	//打开油槽写入数据;
    	char buf[]="客户端写入:匿名管道测试";
    	DWORD dwWrite;
    	if(!WriteFile(hMailSlotClient,buf,strlen(buf)+1,&dwWrite,NULL))//WriteFile()读写管道
    	{
    		MessageBox("客户端写入失败");
    		CloseHandle(hMailSlotClient);
    		return;
    	}
    	CloseHandle(hMailSlotClient);
    }









  • 相关阅读:
    ThreadPoolExecutor的corePoolSize、maximumPoolSize和poolSize
    ThreadPoolExecutor线程池的一个面试题
    SpringBoot 集成Jedis操作set
    死磕JVM之类中各部分的加载顺序
    ThreadLocal为什么会内存泄漏
    有趣的RPC理解
    MQ如何解决消息的顺序性
    Collections.sort排序
    对象的内存分析
    类与对象的分析
  • 原文地址:https://www.cnblogs.com/HuaiNianCiSheng/p/3074712.html
Copyright © 2011-2022 走看看