进程间通信

(1)剪贴板

void CMFCApplication39Dlg::OnBnClickedBtnSend()
{
    // TODO: 在此添加控件通知处理程序代码
    if(OpenClipboard())//打开剪贴板
    {
        CString str;//保存发送编辑框控件上的数据
        HANDLE hClip;//保存调用GlobalAlloc函数后分配的内存对象的句柄
        char *pBuf;//保存调用GlobalLock函数后返回的内存地址
        EmptyClipboard();//清空剪贴板上的数据
        GetDlgItemText(IDC_EDIT_SEND,str);
        hClip = GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);
        pBuf = (char *)GlobalLock(hClip);
        
        int i;
        for(i=0;i<str.GetLength();i++)
        {
            pBuf[i] = str[i];
        }
        pBuf[i] = '\0';
        GlobalUnlock(hClip);
        SetClipboardData(CF_TEXT,hClip);
        CloseClipboard();//关闭剪贴板
    }
}


void CMFCApplication39Dlg::OnBnClickedBtnRecv()
{
    // TODO: 在此添加控件通知处理程序代码
    if(OpenClipboard())//打开剪贴板
    {
        if(IsClipboardFormatAvailable(CF_TEXT))
        {
            HANDLE hClip;//保存调用GlobalAlloc函数后分配的内存对象的句柄
            char *pBuf;//保存调用GlobalLock函数后返回的内存地址    
            hClip = GetClipboardData(CF_TEXT);
            pBuf = (char *)GlobalLock(hClip);
            GlobalUnlock(hClip);
            CString str(pBuf);
            SetDlgItemText(IDC_EDIT_RECV,str);
        }
        CloseClipboard();
    }
}

(2)匿名管道

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

父进程:

BOOL CParentDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	pMenu=new CMenu() ; 
    pMenu->LoadMenu(IDR_MENU1); 
    SetMenu(pMenu);
	hWrite = NULL;
	hRead = NULL;

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}



void CParentDlg::OnPipeCreate()
{
	// TODO: 在此添加命令处理程序代码
	SECURITY_ATTRIBUTES sa;//SECURITY_ATTRIBUTES结构体有三个成员
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);//nLength指定结构体的大小
	sa.lpSecurityDescriptor = NULL;//lpSecurityDescriptor可以传入NULL
	sa.bInheritHandle = TRUE;//bInheritHandle指定返回的句柄能否被一个新的进程继承,如果为TRUE,表示能够被新进程继承
	if(!CreatePipe(&hRead,&hWrite,&sa,0))//创建匿名管道,hRead返回管道的读取句柄,hWrite返回管道的写入句柄,sa是SECURITY_ATTRIBUTES结构体变量,第四个参数表示缓冲区大小,0表示默认大小。
	{
		MessageBox(_T("创建匿名管道失败!"));
		return;
	}
	STARTUPINFO sui;
	PROCESS_INFORMATION pi;
	ZeroMemory(&sui,sizeof(STARTUPINFO));
	sui.cb = sizeof(STARTUPINFO);//cb表示STARTUPINFO结构体的大小
	sui.dwFlags = STARTF_USESTDHANDLES;//如果dwFlags为STARTF_USESTDHANDLES,那么将使用STARTUPINFO的hStdInput,hStdOutput,hStdError设置所创建的新进程的标准输入,标准输出和标准错误句柄。
	sui.hStdInput = hRead;//新进程标准输入句柄
	sui.hStdOutput = hWrite;//新进程标准输出句柄
	sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);//新进程标准错误句柄
	if(!CreateProcess(_T("F:\\代码保存\\Parent\\Debug\\Child.exe"),NULL,NULL,NULL,TRUE,0,NULL,NULL,&sui,&pi))//创建进程,第一个参数表示要创建进程的路径,第四个参数如果为TRUE,
		//那么父进程的每个可继承的打开句柄都能被子进程继承。我们设置为TRUE,让Child继续Parent的读写句柄,第七个参数是指向STARTUPINFO结构体的指针,第八个参数是指向PROCESS_INFORMATION的指针
	{
		CloseHandle(hRead);
		CloseHandle(hWrite);
		hRead = NULL;
		hWrite = NULL;
		MessageBox(_T("创建子进程失败!"));
		return;
	}
	else
	{
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
}


void CParentDlg::OnPipeRead()
{
	// TODO: 在此添加命令处理程序代码
	char buf[100];
	DWORD dwRead;
	if(!ReadFile(hRead,buf,100,&dwRead,NULL))//读取数据
	{
		MessageBox(_T("读取数据失败!"));
		return;
	}
	MessageBox((CString)buf);
}


void CParentDlg::OnPipeWrite()
{
	// TODO: 在此添加命令处理程序代码
	char buf[100]= "http://www.baidu.com";
	DWORD dwWrite;
	if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))//写入数据
	{
		MessageBox(_T("写入数据失败!"));
		return;
	}
}

子进程:

BOOL CChildDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    pMenu = new CMenu;
    pMenu->LoadMenuW(IDR_MENU1);
    SetMenu(pMenu);
    hRead = GetStdHandle(STD_INPUT_HANDLE);//获取子进程的标准输入
    hWrite = GetStdHandle(STD_OUTPUT_HANDLE);//获取子进程的标准输出
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}




void CChildDlg::OnPipeRead()
{
    // TODO: 在此添加命令处理程序代码
    char buf[100];
    DWORD dwRead;
    if(!ReadFile(hRead,buf,100,&dwRead,NULL))
    {
        MessageBox(_T("读取数据失败!"));
        return;
    }
    MessageBox((CString)buf);
}


void CChildDlg::OnPipeWrite()
{
    // TODO: 在此添加命令处理程序代码
    char buf[100]= "匿名管道测试程序";
    DWORD dwWrite;
    if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
    {
        MessageBox(_T("写入数据失败!"));
        return;
    }
}
这样父进程与子进程就能就行通讯了


(3)命名管道

命名管道作为一种通信方法,有其独特的优越性,这主要表现在它不完全依赖于某一种协议,而是适用于任何协议——只要能够实现通信。
  命名管道具有很好的使用灵活性,表现在:
  1) 既可用于本地,又可用于网络。
  2) 可以通过它的名称而被引用。
  3) 支持多客户机连接。
  4) 支持双向通信。
  5) 支持异步重叠I/O操作。

服务器端:

void CNamePipeSrvDlg::OnPipeCreate()
{
	// TODO: 在此添加命令处理程序代码
	m_hPipe = CreateNamedPipe(_T("\\\\.\\pipe\\MyPipe"),PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL);//创建命名管道
	//第一个参数: \\\\.\\pipe\\MyPipe, 必须为这种格式。中间的“.”表示本地机器,如果要跟远程机器建立连接,则需要设定远程服务器的名字。
	//第二个参数:表明管道的访问方式,双向,单向,设置重叠模式等
	//第三个参数:指定管道的模式,为0默认是字节读的方式,阻塞模式
	//第四个参数:指定管道能创建的最大数目
	//第五个参数:指定为输出缓冲区所保留的字节数
	//第六个参数:指定为输入缓冲区所保留的字节数
	//第七个参数:指定默认的超时值
	//第八个参数:命名管道的安全描述符。NULL表示默认。
	if(INVALID_HANDLE_VALUE ==m_hPipe)
	{
		MessageBox(_T("创建命名管道失败!"));
		m_hPipe = NULL;
		return;
	}
	//创建匿名的人工重置事件对象
	HANDLE hEvent;
	hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	if(!hEvent)
	{
		MessageBox(_T("创建事件对象失败!"));
		CloseHandle(m_hPipe);
		m_hPipe = NULL;
		return;
	}
	OVERLAPPED ovlap;
	ZeroMemory(&ovlap,sizeof(OVERLAPPED));
	ovlap.hEvent = hEvent;
	//等待客户端请求的到来
	if(!ConnectNamedPipe(m_hPipe,&ovlap))//第一个参数表示命名管道服务器的句柄,第二个参数指向一个OVERLAPPED结构的指针
	{
		if(ERROR_IO_PENDING != GetLastError())
		{
			MessageBox(_T("等待客户端连接失败!"));
			CloseHandle(m_hPipe);
			CloseHandle(hEvent);
			m_hPipe = NULL;
			return;
		}
	}
	if(WAIT_FAILED == WaitForSingleObject(hEvent,INFINITE))
	{
		MessageBox(_T("等待对象失败!"));
		CloseHandle(m_hPipe);
		CloseHandle(hEvent);
		m_hPipe = NULL;
		return;
	}
	CloseHandle(hEvent);
}


void CNamePipeSrvDlg::OnPipeRead()
{
	// TODO: 在此添加命令处理程序代码
	char buf[100];
	DWORD dwRead;
	if(!ReadFile(m_hPipe,buf,100,&dwRead,NULL))
	{
		MessageBox(_T("读取数据失败"));
		return;
	}
	MessageBox((CString)buf);
}


void CNamePipeSrvDlg::OnPipeWrite()
{
	// TODO: 在此添加命令处理程序代码
	char buf[] = "http://www.baidu.com";
	DWORD dwWrite;
	if(!WriteFile(m_hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
	{
		MessageBox(_T("写入数据失败!"));
		return;
	}
}

客户端:

void CNamePipeCltDlg::OnPipeWrite()
{
	// TODO: 在此添加命令处理程序代码
	char buf[] = "命名管道测试!";
	DWORD dwWrite;
	if(!WriteFile(m_hPipe,buf,sizeof(buf)+1,&dwWrite,NULL))
	{
		MessageBox(_T("写入数据失败!"));
		return;
	}
}


void CNamePipeCltDlg::OnPipeRead()
{
	// TODO: 在此添加命令处理程序代码
	char buf[100];
	DWORD dwRead;
	if(!ReadFile(m_hPipe,buf,100,&dwRead,NULL))
	{
		MessageBox(_T("读取数据失败!"));
		return;
	}
	MessageBox((CString)buf);
}


void CNamePipeCltDlg::OnPipeConnect()
{
	// TODO: 在此添加命令处理程序代码
	//判断是否有可利用的命名管道
	if(!WaitNamedPipe(_T("\\\\.\\pipe\\MyPipe"),NMPWAIT_WAIT_FOREVER))
	{
		MessageBox(_T("当前没有可利用的命名管道!"));
		return;
	}
	//打开可利用的命名管道,并与服务器端进行通讯
	m_hPipe = CreateFile(_T("\\\\.\\pipe\\MyPipe"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if(INVALID_HANDLE_VALUE == m_hPipe)
	{
		MessageBox(_T("打开命名管道失败!"));
		m_hPipe = NULL;
		return;
	}
}



(4)邮槽

邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输。邮槽是一种单向通信机制,创建邮槽的服务器读取数据,打开邮槽的客户机写入数据。邮槽是利用广播通信的,也就是说,邮槽可以实现一对多的单向通信。

服务器端:

BOOL CMailSoltSrvDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	HANDLE hMailslot;
	//创建邮槽
	hMailslot = CreateMailslot(_T("\\\\.\\mailslot\\MyMailSlot"),0,MAILSLOT_WAIT_FOREVER,NULL);

	if(INVALID_HANDLE_VALUE == hMailslot)
	{
		MessageBox(_T("创建邮槽失败"));
		return TRUE;
	}

	char buf[100];

	DWORD dwRead;
	//从邮槽读取数据
	if(!ReadFile(hMailslot,buf,100,&dwRead,NULL))
	{
		MessageBox(_T("读取数据失败"));
		CloseHandle(hMailslot);
		return TRUE;
	}

	MessageBox((CString)buf);
	CloseHandle(hMailslot);

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

客户端:
BOOL CMailSlotCltDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	HANDLE hMailSlot;

	//打开邮槽
	hMailSlot = CreateFile(_T("\\\\.\\mailslot\\MyMailslot"),GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

	if(INVALID_HANDLE_VALUE == hMailSlot)
	{
		MessageBox(_T("打开邮槽失败!"));
		return TRUE;
	}
	char buf[] = "http://www.baidu.com";
	DWORD dwWrite;
	//向邮槽写入数据
	if(!WriteFile(hMailSlot,buf,sizeof(buf)+1,&dwWrite,NULL))
	{
		MessageBox(_T("写入数据失败!"));
		return TRUE;
	}
	CloseHandle(hMailSlot);

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

小结:这四种通信方式,其中剪贴板和匿名管道只能实现同一台机器上两个进程间的通信,而不能实现跨网络的通信,而命名管道和邮槽不仅可以实现本地的通信,还可以实现跨网络的通信。而命名管道是一对一通信,邮槽是一对多的通信,但是邮槽传输的数据量小,可以根据具体情况选用合适的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值