[转载]使用命名管道实现进程间通信

使用命名管道实现进程间通信
来源 : VChelp

4.5 进程间通信

在Win32下提供的进程间通信方式有以下几种:

剪贴板Clipboard:在16位时代常使用的方式,CWnd类中提供了支持。
COM/DCOM:通过COM系统的代理存根方式进行进程间数据交换,但只能够表现在对接口函数的调用时传送数据,通过DCOM可以在不同主机间传送数据。
Dynamic Data Exchange (DDE):在16位时代常使用的方式。
File Mapping:文件映射,在32位系统中提供的新方法,可用来共享内存。
Mailslots:邮件槽,在32位系统中提供的新方法,可在不同主机间交换数据,分为服务器方和客户方,双方可以通过其进行数据交换,在Win9X下只支持邮件槽客户。
Pipes:管道,分为无名管道:在父子进程间交换数据;有名管道:可在不同主机间交换数据,分为服务器方和客户方,在Win9X下只支持有名管道客户。
RPC:远程过程调用,很少使用,原因有两个:复杂而且与UNIX系统的RCP并不完全兼容。但COM/DCOM的调用是建立在RPC的基础上的。
Windows Sockets:网络套接口,可在不同主机间交换数据,分为服务器方和客户方。(相关介绍见Visual C++/MFC入门教程 第六章 网络通信开发)
WM_COPYDATA:通过发送WM_COPYDATA消息并将数据放在参数中来传递数据给其他进程。
下面主要介绍一下命名管道的用法,命名管道是一个有名字,单向或双向的通信管道。管道的名称有两部分组成:计算机名和管道名,例如\\[host_name]\pipe\[pipe_name]\(括号内为参数)。对于同一主机来讲允许有多个同一命名管道的实例并且可以由不同的进程打开,但是不同的管道都有属于自己的管道缓冲区而且有自己的通讯环境互不影响,并且命名管道可以支持多个客户端连接一个服务器端。命名管道客户端不但可以与本机上的服务器通讯也可以同其他主机上的服务器通讯。

命名管道的连接和通讯采用如下方式:

在服务器端第一次创建命名管道后等待连接,当客户端连接成功后服务器端的命名管道就用作通讯用途。如果需要再次等待连接,服务器端就需要再次打开命名管道(创建一个命名管道的实例)并等待连接。
对于客户端每次打开命名管道后建立与服务器间的连接,然后就可以利用命名管道进行通信,如果需要建立第二个连接则需要再次打开管道和再次建立连接。
创建命名管道时需要指定一个主机名和管道名,对于客户端来说可以是如下格式:\\[host_name]\pipe\[pipe_name]\也可以是\\.\pipe\pipe_name\其中.表示本机。而服务器端只能够在指定本机作为主机名,即只能使用下面的格式:\\.\pipe_name\。此外需要记住,在同一主机上管道名称是唯一的,一个命名管道一旦被创建就不允许相同名称的管道再被创建。

服务器方通过:

HANDLE CreateNamedPipe(
  LPCTSTR lpName,                             // pipe name
  DWORD dwOpenMode,                           // pipe open mode
  DWORD dwPipeMode,                           // pipe-specific modes
  DWORD nMaxInstances,                        // maximum number of instances
  DWORD nOutBufferSize,                       // output buffer size
  DWORD nInBufferSize,                        // input buffer size
  DWORD nDefaultTimeOut,                      // time-out interval
  LPSECURITY_ATTRIBUTES lpSecurityAttributes  // SD
);
创建命名管道和打开已经存在的命名管道,其中lpName为管道名称,dwOpenMode为创建方式,可以是下面值的组合:
PIPE_ACCESS_INBOUND:管道只能用作接收数据。
PIPE_ACCESS_OUTBOUND:管道只能用作发送数据。
PIPE_ACCESS_DUPLEX:管道既可以发送也可以接收数据。(上面这三个值只能够取其中一个)
FILE_FLAG_WRITE_THROUGH:管道用于同步发送和接收数据,只有在数据被发送到目标地址时发送函数才会返回,如果不设置这个参数那么在系统内部对于命名管道的处理上可能会因为减少网络附和而在数据积累到一定量时才发送,并且对于发送函数的调用会马上返回。
FILE_FLAG_OVERLAPPED:管道可以用于异步输入和输出,异步读写的有关方法和文件异步读写是相同的。
dwPipeMode指定管道类型,可以是下面值的组合:
PIPE_TYPE_BYTE:数据在通过管道发送时作为字节流发送,不能与PIPE_READMODE_MESSAGE共用。
PIPE_TYPE_MESSAGE:数据在通过管道发送时作为消息发送,不能与PIPE_READMODE_BYTE共用。
PIPE_READMODE_BYTE:在接收数据时接收字节流。
PIPE_READMODE_MESSAGE:在接收数据时接收消息。
PIPE_WAIT:使用等待模式,在读,写和建立连接时都需要管道的另一方完成相应动作后才会返回。
PIPE_NOWAIT:使用非等待模式,在读,写和建立连接时不需要管道的另一方完成相应动作后就会立即返回。
nMaxInstances为管道的的最大数量,在第一次建立服务器方管道时这个参数表明该管道可以同时存在的数量。PIPE_UNLIMITED_INSTANCES表明不对数量进行限制。nOutBufferSize和nInBufferSize表示缓冲区的大小。nDefaultTimeOut表示在等待连接时最长的等待时间(以毫秒为单位),如果在创建时设置为NMPWAIT_USE_DEFAULT_WAIT表明无限制的等待,而以后服务器方的其他管道实例也需要设置相同的值。lpSecurityAttributes为安全属性,一般设置为NULL。如果创建或打开失败则返回INVALID_HANDLE_VALUE。可以通过GetLastError得到错误。
客户方通过:

HANDLE CreateFile(
  LPCTSTR lpFileName,                         // file name
  DWORD dwDesiredAccess,                      // access mode
  DWORD dwShareMode,                          // share mode
  LPSECURITY_ATTRIBUTES lpSecurityAttributes, // SD
  DWORD dwCreationDisposition,                // how to create
  DWORD dwFlagsAndAttributes,                 // file attributes
  HANDLE hTemplateFile                        // handle to template file
);
创建客户端命名管道,CreateFile可以有很多用途,可以用来创建文件,管道,邮件槽,目录等,这里介绍用CreateFile来打开客户端命名管道。lpFileName用来指明管道名称。dwDesiredAccess用来表明使用方式,可以使用下面的值:
GENERIC_READ:打开一个只用于读的管道。
GENERIC_WRITE:打开一个只用于写的管道。
GENERIC_READ | GENERIC_WRITE:打开一个用于读和写的管道。
dwShareMode指定共享方式,一般指定为0,lpSecurityAttributes为安全属性,一般设置为NULL,dwCreationDisposition设置为OPEN_EXISTING,dwFlagsAndAttributes设置为FILE_ATTRIBUTE_NORMAL,此外可以还设置为FILE_FLAG_OVERLAPPED来进行异步通讯,hTemplateFile设置为NULL。如果打开失败则返回INVALID_HANDLE_VALUE。可以通过GetLastError得到错误。
此外客户方可以利用:

BOOL CallNamedPipe(
  LPCTSTR lpNamedPipeName,  // pipe name
  LPVOID lpInBuffer,        // write buffer
  DWORD nInBufferSize,      // size of write buffer
  LPVOID lpOutBuffer,       // read buffer
  DWORD nOutBufferSize,     // size of read buffer
  LPDWORD lpBytesRead,      // number of bytes read
  DWORD nTimeOut            // time-out value
);
来创建一个发送消息的管道。
管道的连接管理,客户方在调用CreateFile后立即就能够建立服务器的连接,而服务器方一旦管道打开或创建后可以用

BOOL ConnectNamedPipe(
  HANDLE hNamedPipe,          // handle to named pipe
  LPOVERLAPPED lpOverlapped   // overlapped structure
);
来等待客户端的连接建立。如果希望在服务器方检测是否有连接到达,可以调用
BOOL WaitNamedPipe(
  LPCTSTR lpNamedPipeName,  // pipe name
  DWORD nTimeOut            // time-out interval
);

这里的lpNamePipeName直接使用创建管道时的名称,如果在服务器方希望关闭连接则调用
BOOL DisconnectNamedPipe(
  HANDLE hNamedPipe   // handle to named pipe
);

一旦连接被关闭,服务器方可以再次调用ConnectNamedPipe来建立连接。如果要关闭管道则直接调用CloseHandle。请注意这里提到的关闭管道和关闭连接是不同的意思,在同一个管道上可以依次反复建立连接,而且可以减小系统的负荷。而且如果指定了管道最大数量限制那么在打开的管道达到最大限制后如果不关闭旧管道就无法打开新管道。

对于客户方则无法关闭连接,而只能直接调用CloseHandle关闭管道。

数据的发送,不论是服务器还是客户方都可以通过ReadFile和WriteFile进行管道读写来达到通讯的目的。

下面是一个例子,服务器方创建或打开一个管道并读入对方发送的数据,将小写字母转换成大写字母后返回,而客户发创建一个到服务器的连接并发送一个字符串并读回经过转换的数据:

在使用这个例子时,运行三个服务端进程,而运行第四个时会因为达到管道数量限制而打开管道失败。

//服务方
void CNamed_pipeDlg::OnCreateP()
{
    DWORD dwTO = NMPWAIT_USE_DEFAULT_WAIT;//设置连接等待时间
    HANDLE hSvr = CreateNamedPipe("\\\\.\\pipe\\test_pipe\\",PIPE_ACCESS_DUPLEX,PIPE_TYPE_BYTE,3,256,256,dwTO,NULL);
    if( INVALID_HANDLE_VALUE == hSvr)
    {
        AfxMessageBox("Error create/open pipe");
    }
    else
    {
        if (ConnectNamedPipe(hSvr,NULL))
        {
            BYTE bRead;
            DWORD dwRead,dwWritten;
            while (ReadFile(hSvr,&bRead,1,&dwRead,NULL))
            {
                if(bRead >= 'a' && bRead $lt;='z')
                    bRead = 'A'+ (bRead-'a');
                WriteFile(hSvr,&bRead,1,&dwWritten,NULL);
            }
        }
        else
        {
            AfxMessageBox("error when waiting connected");
        }
        CloseHandle(hSvr);
    }
}
//客户端
void CNamed_pipe_cDlg::OnConn()
{
    HANDLE hClient = CreateFile("\\\\.\\pipe\\test_pipe\\",GENERIC_WRITE |GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hClient == INVALID_HANDLE_VALUE)
    {
        AfxMessageBox("Error open pipe");
    }
    else
    {
            DWORD dwRead,dwWritten;
            char szSend[10]="send...";
            char szRecv[10];
            for(int i=0;i<strlen(szSend)+1;i++)
            {
                WriteFile(hClient,szSend+i,1,&dwWritten,NULL);
                ReadFile(hClient,szRecv+i,1,&dwRead,NULL);
            }
            CloseHandle(hClient);//close pipe
            AfxMessageBox(szRecv);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/407207.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML DOM之标签操作方法

1.document.getElementById(id)方法可返回对拥有指定 ID 的第一个对象的引用 2.document.getElementsByName(name)方法可返回带有指定名称的对象的集合 3.document.getElementsByTagName(tagname)方法可返回带有指定标签名的对象的集合。如果把特殊字符串 “*” 传递给 getEle…

Vue中动态(import 、require)显示img图片

vue中&#xff0c;经常会遇到显示图片的问题&#xff0c; 如果是一个普通组件的话&#xff0c;那么这样就可以了 <img src"../assets/images/avtor.jpg" width"100%"> 上文的弊端有两个&#xff1a; 首先&#xff0c;是采用绝对路径引入。如果以…

案例精解企业级网络构建

早就听说51CTO博客出书了,但由于放假在家,没有来得及购买.现在开学了,天天上51CTO网站,博客出书的广告打的到处都是,嘿嘿!~~想不关注都不行啊!看了各位博友对这本书的好评,终于禁不住诱惑,也在网上购买了一本.今天终于收到书了.打开包装,书真的很精美.自己非常喜欢,我是一名专科…

Oracle 中 for update 和 for update nowait 的区别

原文出处http://bijian1013.iteye.com/blog/1895412 一.for update 和 for update nowait 的区别 首先一点&#xff0c;如果只是select 的话&#xff0c;Oracle是不会加任何锁的&#xff0c;也就是Oracle对 select 读到的数据不会有任何限制&#xff0c;虽然这时候有可能另外一…

HTML DOM之节点操作方法(1)

1.checkboxObject.focus()方法用于为 checkbox 赋予焦点 2.checkboxObject.blur()方法用于让 checkbox 失去焦点 3.appendChild()在子节点列表之后插入新增的子节点 注&#xff1a;您也可以使用 appendChild()方法将一个元素移动到另一个元素中 这里就将”myList2”中最后一个…

常用端口号

端口号标识了一个主机上进行通信的不同的应用程序。 1.HTTP协议代理服务器常用端口号&#xff1a;80/8080/3128/8081/90982.SOCKS代理协议服务器常用端口号&#xff1a;10803.FTP&#xff08;文件传输&#xff09;协议代理服务器常用端口号&#xff1a;214.Telnet&#xff08;…

关于停止发表“每周新闻回顾”的通知

各位朋友&#xff1a;从2007年春节之后&#xff0c;老杨就基本上坚持每周整理当周重大IT新闻&#xff0c;如此坚持了一年。之后&#xff0c;由51CTO编辑部各位编辑轮流进行这项工作&#xff0c;算来已经超过一年半了。承蒙各位读者厚爱&#xff0c;如今新闻回顾已经成为51CTO.c…

单词统计程序

一个简单的单词统计程序&#xff0c; 问题来源: http://topic.csdn.net/u/20111114/10/2e439bbf-04c5-4042-9905-ece0bf008b97.html /* 功能&#xff1a;实现单词统计功能 */#include <stdio.h> #include <string.h>main() {char *t[20]; // 声明一个指针数组&a…

利用jQuery实现的Ajax 验证用户名是否存在

异步刷新实现方式有多种&#xff0c;也可以借助JS的多种框架&#xff0c;下面是使用jQuery框架实现的AJAX 验证用户名是否存在 jQuery.ajax概述 HTTP 请求加载远程数据。 通过jQuery 底层 AJAX 实现。简单易用的高层实现见 $.get, $.post 等。$.ajax() 返回其创建的 XMLHttpReq…

HTML DOM之节点操作方法(2)

9.document.hasFocus()方法返回布尔值&#xff0c;用于检测文档(或文档内的任一元素)是否获取焦点。没有参数 10.node.hasChildNodes()方法返回 true&#xff0c;如果指定节点拥有子节点&#xff0c;否则返回 false。没有参数 11.node.isDefaultNamespace(namespaceURI)方法返回…

git clone、git pull和git fetch的用法及区别

1.git clone git clone顾名思义就是将其他仓库克隆到本地&#xff0c;包括被clone仓库的版本变化。举个例子&#xff0c;你当前目录比方说是在e:/course/中&#xff0c;此时若想下载远程仓库&#xff0c;本地无需git init,直接git clone url&#xff08;url是你远程仓库的地址…

求一个整数的阶乘结果中后缀0的个数

问题描述&#xff1a; 给一个整数&#xff0c;请输出该数字阶乘的后缀0的个数&#xff0c;例如&#xff1a; 数字7&#xff0c;它的阶乘为5040&#xff0c;后面有一个0&#xff0c;则输出1&#xff1b;还有数字10&#xff0c;它的阶乘为3628800&#xff0c;后面有两个0&#x…

(转载)Android两种Tab分页的方式:TabActivity和ActivityGroup以及Android项目几种常见的应用架构...

在Android里面Tab分页&#xff0c;常用的方法有两种&#xff1a; 一、TabActivity和TabHost的结合 1.主类继承TabActivity public class Tagpage extends TabActivity 2.获取当前TabHost对象 final TabHost tabHost getTabHost(); 3.添加Tab分页标签,这里就是关键&#xff0c;…

CSS3之Transition

css的transition允许css的属性值在一定的时间区间内平滑地过渡。这种效果可以在鼠标单击、获得焦点、被点击或对元素任何改变中触发&#xff0c;并圆滑地以动画效果改变CSS的属性值 1.语法&#xff1a;transition: property duration timing-function delay; 参数1&#xff1…

解决qrcode动态生成二维码时多次点击生成多个二维码的问题

getEwm(url){document.getElementById("qrcode").innerHTML "";var qrcode new QRCode(this.$refs.qrCodeUrl, {text: url,width: 200,height: 200,colorDark: #000000,colorLight: #ffffff,correctLevel: QRCode.CorrectLevel.H})},即生成二维码之前先将…

无线运维——J2ME和WAP运维方式的优缺点

随着信息技术的发展&#xff0c;软件产品进入了多接入渠道的新阶段&#xff0c;这些接入渠道既包括传统的Socket、Web等方式&#xff0c;也包含WAP, SMS,EMAIL等方式。网络管理软件作为软件产品的一个小的分支&#xff0c;在多接入渠道方面&#xff0c;也有了很大的发展。今天我…