进程间通信

来源:互联网 发布:苹果vr软件 编辑:程序博客网 时间:2024/06/05 03:07

(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可以传入NULLsa.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}

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

0 0