2.4实验四:使用命名管道实现进程通信
- 格式:doc
- 大小:84.50 KB
- 文档页数:6
进程间通信-命名管道实现引⼦好,到这⾥呢,就需要介绍实现进程间通信的第四种⽅式了,也就是通过命名管道来实现,前⾯介绍的那三种⽅式呢,都是有缺陷或者说局限性太强,⽽这⾥介绍的命名管道相对来说,在这⽅⾯就做得好很多了,⽐如,剪贴板的话只能实现本机上进程之间的通信,⽽邮槽的话虽然是可以实现跨⽹络之间的进程的通信,但⿇烦的是邮槽的服务端只能接收数据,邮槽的客户端只能发送数据,太悲剧了,⽽对于匿名管道的话,其也只能实现本机上进程之间的通信,你要是能够实现本机进程间的通信也就算了,关键是它还只⽤来实现本地的⽗⼦进程之间的通信,也太局限了吧?⽽这⾥介绍的这个命名管道的话,就和他们有些不同了,在功能上也就显得强⼤很多了,⾄少其可以实现跨⽹络之间的进程的通信,同时其客户端既可以接收数据也可以发送数据,服务端也是既可以接收数据,⼜可以发送数据的。
命名管道概述命名管道是通过⽹络来完成进程之间的通信的,命名管道依赖于底层⽹络接⼝,其中包括有 DNS 服务,TCP/IP 协议等等机制,但是其屏蔽了底层的⽹络协议细节,对于匿名管道⽽⾔,其只能实现在⽗进程和⼦进程之间进⾏通信,⽽对于命名管道⽽⾔,其不仅可以在本地机器上实现两个进程之间的通信,还可以跨越⽹络实现两个进程之间的通信。
命名管道使⽤了 Windows 安全机制,因⽽命名管道的服务端可以控制哪些客户有权与其建⽴连接,⽽哪些客户端是不能够与这个命名管道建⽴连接的。
利⽤命名管道机制实现不同机器上的进程之间相互进⾏通信时,可以将命名管道作为⼀种⽹络编程⽅案时,也就是看做是 Socket 就可以了,它实际上是建⽴了⼀个客户机/服务器通信体系,并在其中可靠的传输数据。
命名管道的通信是以连接的⽅式来进⾏的,服务器创建⼀个命名管道对象,然后在此对象上等待连接请求,⼀旦客户连接过来,则两者都可以通过命名管道读或者写数据。
命名管道提供了两种通信模式:字节模式和消息模式。
在字节模式下,数据以⼀个连续的字节流的形式在客户机和服务器之间流动,⽽在消息模式下,客户机和服务器则通过⼀系列的不连续的数据单位,进⾏数据的收发,每次在管道上发出⼀个消息后,它必须作为⼀个完整的消息读⼊。
C++进程通信之命名管道命名管道定义⼀个命名管道是⼀个命名的,单向或双⾯管道的管道服务器和⼀个或多个管道客户端之间的通信。
命名管道的所有实例共享相同的管道名称,但每个实例都有⾃⼰的缓冲区和句柄,并为客户端/服务器通信提供单独的管道。
实例的使⽤使多个管道客户端能够同时使⽤同⼀个命名管道。
这⾥要理解实例的概念:当我⽤CreateNamedPipe在服务器端创建⼀个名为pipeTest的命名管道时,即pipeTest拥有了⼀个实例。
再次重复刚才的操作时,即创建了pipeTest的第⼆个实例;当⽤CreateNamedPipe在服务器端创建⼀个名为pipeTestAnother的命名管道时,则该pipeTestAnother管道拥有了第⼀个实例。
命名管道的使⽤步骤服务器端:⾸先,使⽤创建属于该管道的实例。
然后等待客户端实例的连接,服务器端可以使⽤ConnectNamedPipe进⾏阻塞同步等待客户端实例的连接,也可以⾮阻塞,然后执⾏ReadFile不停读取客户端发送到管道的数据。
客户端:执⾏WaitNamedPipe(不是真正的⽤于连接的函数)来等待管道的出现,存在管道后,执⾏CreateFile来连接存在的服务器管道,获取对应句柄后,执⾏WriteFile往管道发送数据。
上⾯是以最简单的单向的客户端发送数据进管道,服务器端接受管道数据。
还有其他的通信选项。
包括双通道的Read&Write。
Read&Write过程中的同步与异步;按字节流⽅式/消息的⽅式写⼊/读取管道数据。
CreateNamedPipeHANDLE CreateNamedPipeA([in] LPCSTR lpName,[in] DWORD dwOpenMode,[in] DWORD dwPipeMode,[in] DWORD nMaxInstances,[in] DWORD nOutBufferSize,[in] DWORD nInBufferSize,[in] DWORD nDefaultTimeOut,[in, LPSECURITY_ATTRIBUTES lpSecurityAttributes);功能:创建命名管道的实例并返回⽤于后续管道操作的句柄。
第1篇一、实验目的1. 理解进程通信的概念和原理;2. 掌握进程通信的常用机制和方法;3. 能够使用进程通信机制实现进程间的数据交换和同步;4. 增强对操作系统进程管理模块的理解。
二、实验环境1. 操作系统:Linux2. 编程语言:C3. 开发环境:GCC三、实验内容1. 进程间通信的管道机制2. 进程间通信的信号量机制3. 进程间通信的共享内存机制4. 进程间通信的消息队列机制四、实验步骤1. 管道机制(1)创建管道:使用pipe()函数创建管道,将管道文件描述符存储在两个变量中,分别用于读和写。
(2)创建进程:使用fork()函数创建子进程,实现父子进程间的通信。
(3)管道读写:在父进程中,使用read()函数读取子进程写入的数据;在子进程中,使用write()函数将数据写入管道。
(4)关闭管道:在管道读写结束后,关闭对应的管道文件描述符。
2. 信号量机制(1)创建信号量:使用sem_open()函数创建信号量,并初始化为1。
(2)获取信号量:使用sem_wait()函数获取信号量,实现进程同步。
(3)释放信号量:使用sem_post()函数释放信号量,实现进程同步。
(4)关闭信号量:使用sem_close()函数关闭信号量。
3. 共享内存机制(1)创建共享内存:使用mmap()函数创建共享内存区域,并初始化数据。
(2)映射共享内存:在父进程和子进程中,使用mmap()函数映射共享内存区域。
(3)读写共享内存:在父进程和子进程中,通过指针访问共享内存区域,实现数据交换。
(4)解除映射:在管道读写结束后,使用munmap()函数解除映射。
4. 消息队列机制(1)创建消息队列:使用msgget()函数创建消息队列,并初始化消息队列属性。
(2)发送消息:使用msgsnd()函数向消息队列发送消息。
(3)接收消息:使用msgrcv()函数从消息队列接收消息。
(4)删除消息队列:使用msgctl()函数删除消息队列。
[转载]使⽤命名管道实现进程间通信使⽤命名管道实现进程间通信来源 : VChelp4.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]\(括号内为参数)。
对于同⼀主机来讲允许有多个同⼀命名管道的实例并且可以由不同的进程打开,但是不同的管道都有属于⾃⼰的管道缓冲区⽽且有⾃⼰的通讯环境互不影响,并且命名管道可以⽀持多个客户端连接⼀个服务器端。
命名管道客户端不但可以与本机上的服务器通讯也可以同其他主机上的服务器通讯。
进程的管道通信实验是一个非常有用的实验,它允许两个进程之间进行数据交换。
这个实验主要涉及到了管道、管道缓冲区以及进程之间的通信机制。
以下是对这个实验的总结:
1. 管道的概念和作用:
管道是一种用于进程间通信的机制,它允许两个进程之间进行数据交换。
在管道通信实验中,我们创建了一个管道,并使用它来在两个进程之间传递数据。
管道的作用是连接两个进程,使得它们可以相互发送和接收数据。
2. 管道缓冲区:
管道缓冲区是管道中的一个重要概念。
当一个进程向管道写入数据时,数据会被写入缓冲区中,等待另一个进程读取。
当缓冲区中的数据被读取后,缓冲区中的数据会被移除,为新的数据腾出空间。
3. 进程间的通信:
在管道通信实验中,我们创建了两个进程,并使用管道来在它们之间进行通信。
一个进程向管道写入数据,另一个进程从管道读取数据。
通过这种方式,两个进程可以相互发送和接收数据。
4. 实验中的问题和解决方案:
在实验中,我们遇到了一些问题,如管道中的数据读写错误、进程间的通信问题等。
为了解决这些问题,我们采取了一些措施,如检查数据的读写是否正确、确保进程间的通信畅通等。
5. 实验的意义和收获:
通过这个实验,我们深入了解了进程间通信的概念和机制,并掌握了管道通信的基本原理和方法。
此外,我们还学会了如何解决实验中遇到的问题,提高了我们的编程能力和解决问题的能力。
总之,进程的管道通信实验是一个非常有意义的实验,它让我们深入了解了进程间通信的原理和方法。
通过这个实验,我们不仅掌握了相关的知识和技能,还提高了我们的编程能力和解决问题的能力。
实验四:进程通信实验实验学时:3学时一、实验目的1、熟悉操作系统进程通信原理2、设计程序,实现共享内存、管道通信、消息通信二、实验基本原理1、进程间通信的几种方法简介(1)消息队列:消息队列是消息的链接表,包括Posix消息队列systemV消息队列。
有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。
(2)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。
是针对其他通信机制运行效率较低而设计的。
往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(3)无名管道(Pipe)及有名管道(named pipe):有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;无名管道可用于有亲缘关系的进程之间彼此的通信,进行通信时候必须有一定的机制保证对管道写和读的互斥:即在读是要关闭写的端口,而在写的时候也要保证读的一端是关闭的。
2、进程通信函数(1)消息队列有关系统调用函数a.创建消息队列使用msgget()函数:#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int flag) ;该函数成功调用返回消息队列标识符。
其中的key是关键字,可以由ftok()函数得到:key=ftok(“.”,’a’);其中”.”可以是任何目录,’a’是任意字符,即所有群组标识。
flag是标识,IPC_CREAT位表示创建,一般由服务器程序创建消息队列时使用。
如果是客户程序,必须打开现存的消息队列,必须不使用IPC_CREAT。
发送和接收的消息都必须使用一个类似msgbuf的结构表示,msgbuf结构定义如下:struct msgbuf{long mtype;char mtext[1];}上面的定义,消息内容只有一个字节,是不实用的,一般我们需要重新定义一个结构:struct amsgbuf{long mtype;char mtext[200];}其中的mtype都是消息类型。
操作系统实验报告用管道实现进程通信1. 实验目的(1)了解Windows系统环境下的进程通信机制。
(2)熟悉Windows系统提供的进程通信API。
2. 实验预备知识(1)根据《计算机操作系统实验指导》中相应内容填写(2)3. 实验内容一个基于有名管道的C/S模式应用,客户端发送命令到服务器,服务器执行命令,并将命令返回信息回传给客户端要求:A.客户端进程完成的工作1.建立私有有名管道2.打开服务端的共有有名管道3.等待用户输入命令4.将私有管道名和命令写入公有管道5.从私有管道中读服务端返回的结果B.服务端进程完成的工作1.建立服务端公有有名管道2.从公有有名管道中读取客户数据3.执行命令,并将结果写入客户私有管道4.实验代码服务器程序:// PipeClient.cpp : Defines the entrypoint for the console application.//#include "stdafx.h"#include "PipeClient.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifCWinApp theApp;using namespace std;int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {BOOL rc=0;char lpName[]="\\\\.\\pipe\\myPipe";char InBuffer[50]="";char OutBuffer[50]="";DWORD BytesRead;int nRetCode=0; int err=0;while(1){strcpy(InBuffer,"");strcpy(OutBuffer,"");printf("Input Data Please!\n");scanf("%s",InBuffer);rc=strcmp(InBuffer,"end");if(rc=0){rc=CallNamedPipe(lpName,InBuffer,sizeof(InBuffer) ,OutBuffer,sizeof(OutBuffer),&BytesRead,NMPWAIT_USE_DEFAULT_ WAIT);break;}rc=WaitNamedPipe(lpName,NMPWAIT_WAIT_FOREVER);if(rc==0){err=GetLastError();printf("Wait Pipe Fail!err=%d\n",err);exit(1);}else printf("Wait Pipe Success!\n");rc=CallNamedPipe(lpName,InBuffer,sizeof(InBuffer) ,OutBuffer,sizeof(OutBuffer),&BytesRead,NMPWAIT_USE_DEFAULT_W AIT);rc=strcmp(OutBuffer,"end");if(rc==0) break;if(rc==0){err=GetLastError();printf("Pipe Call Fail!err=%d\n",err);exit(1);}else printf("Pipe Call Success!\nData from Server is %s\n",OutBuffer);}printf("Now Client to be END\n");return nRetCode;}客户端程序:// 24.cpp : Defines the entry point for the console application.#include "stdafx.h"#include "PipeServer.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////// //////////////////////////// The one and only application objectCWinApp theApp;using namespace std;int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {int nRetCode = 0;int err;BOOL rc;HANDLE hPipeHandle1;char lpName[]="\\\\.\\pipe\\myPipe";char InBuffer[50]="";char OutBuffer[50]="";DWORD BytesRead,BytesWrite;hPipeHandle1=CreateNamedPipe((LPCTSTR)lpName,PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED|WRITE_DAC ,PIPE_TYPE_MESSAGE|PIPE_READMODE_BYTE|PIPE_WAIT, 1,20,30,NMPWAIT_USE_DEFAULT_WAIT,(LPSECURITY_ATTRIBUTES)NULL);if((hPipeHandle1==INVALID_HANDLE_VALUE)||(hPipeHand le1==NULL)){err=GetLastError();printf("Server Pipe Create Fail!err=%d\n");exit(1);}else printf("Server Pipe Create Success!\n");while(1){//guangdaorc=ConnectNamedPipe(hPipeHandle1,(LPOVERLAPPED)NU LL);if(rc==0){err=GetLastError();printf("Server Pipe Conner Fail err=%d\n",err);exit(2);}else printf("Server Pipe Conner Success!\n");strcpy(InBuffer,"");strcpy(OutBuffer,"");//命名管道读数据rc=ReadFile(hPipeHandle1,InBuffer,sizeof(InBuffer ),&BytesRead,(LPOVERLAPPED)NULL);if(rc==0&&BytesRead==0){err=GetLastError();printf("Server Read Pipe Fail!err=%d\n",err);exit(3);}else{printf("Server Read Pipe Success!\nDATA from Client is=%s\n",InBuffer);}rc=strcmp(InBuffer,"end");if(rc==0) break;printf("Please Input Data to Send\n");scanf("%s",OutBuffer);//向管道写数据rc=WriteFile(hPipeHandle1,OutBuffer,sizeof(OutBuf fer),&BytesWrite,(LPOVERLAPPED)NULL);if(rc==0) printf("Server Write Pipe Fail!\n");else printf("Server Write Pipe Success!\n");DisconnectNamedPipe(hPipeHandle1);rc=strcmp(OutBuffer,"end");if(rc==0) break;}printf("Now Server be END!\n");CloseHandle(hPipeHandle1);return nRetCode;}。
Linux进程间通信-命名管道前⾯我们讲了进程间通信的⼀种⽅式,。
我们知道,匿名管道只能⽤于⽗⼦关系的进程之间。
那么没有这种关系的进程之间该如何进⾏数据传递呢?1.什么是命名管道匿名管道是在缓存中开辟的输出和输⼊⽂件流的空间,只能⽤于⽗⼦关系的进程之间。
因为⽗⼦进程的输⼊和输出⽂件描述符是⼀致的。
命名管道是⼀种实际存在的FIFO⽂件,称作“管道⽂件”,⽤于不同进程之间,命名管道进程间打开同⼀个FIFO⽂件,进⾏数据传递。
我们可以像普通⽂件⼀样操作FIFO⽂件。
不同进程,引⽤同⼀个FIFO⽂件,进⾏数据传递。
2.创建命名管道mkfifo函数:创建⼀个命名管道int mkfifo(const char *filename,mode_t mode);filename:指定FIFO⽂件的名称mode:指定⽂件的读写权限3.访问命名管道打开FIFO⽂件有四种⽅式:open(const char *filename,O_RDONLY);open(const char *filename,O_RDONLY|O_NONBLOCK);open(const char *filename,O_WRONLY);open(const char *filename,O_WRONLY|O_NONBLOCK);需要注意的是,不能以O_RDWR模式打开FIFO⽂件,因为这样⼀个进程写⼊的数据会被该进程读取,FIFO⼀般只⽤做单向的数据传递。
open函数的第⼆个参数,表⽰是读管道,还是写管道。
O_NONBLOCK表⽰FIFO管道的读写是⾮阻塞的,默认的话,是阻塞的。
那么何为阻塞呢?⼀个进程写模式打开管道的时候,必须有另⼀个进程以读模式打开;或读模式的时候,必须有另⼀个进程写写模式打开,否则该进程open函数阻塞,直到满⾜以上关系。
⾮阻塞,意味着open函数会⽴即返回,若没有其他进程以只读⽅式打开,open返回-1,并且FIFO也不会被打开。
实验四 进程间通信一、实验目的1. 掌握利用管道机制实现进程间的通信的方法2. 掌握利用消息缓冲队列机制实现进程间的通信的方法3. 掌握利用共享存储区机制实现进程间的通信的方法4. 了解Linux系统中进程软中断通信的基本原理二、实验学时2学时三、实验内容1.掌握实现进程间通信的系统调用的功能和方法进程通信,是指进程之间交换信息。
从这个意义上讲,进程之间的同步、互斥也是一种信息交换,也是一种通信。
但是,这里所说的“通信”是指进程之间交换较多的信息这样一种情况,特别是在由数据相关和有合作关系的进程之间,这种信息交换是十分必要和数量较大的。
进程间通信是协调解决多个进程之间的约束关系,实现进程共同进展的关键技术,是多道系统中控制进程并发执行必不可少的机制。
(1)进程的通信方式:a. 直接通信是指信息直接传递给接收方,如管道。
在发送时,指定接收方的地址或标识,。
在接收时,允许接收来自任也可以指定多个接收方或广播式地址, send(Receiver, message)。
意发送方的消息,并在读出消息的同时获取发送方的地址, receive(Sender,message)b. 间接通信:借助于收发双方进程之外的共享数据结构作为通信中转,如消息队列。
这种数据结构称为缓冲区或信箱。
通常收方和发方的数目可以是任意的。
(2)进程间通信的类型:a. 共享存储器系统:基于共享数据结构的通信方式:只能传递状态和整数值(控制信息),包括进程互斥和同步所采用的信号量机制。
速度快,但传送信息量小,编程复杂,属于低级通信;基于共享存储区的通信方式:能够传送任意数量的数据,属于高级通信。
b. 消息传递系统:在消息传递系统中,进程间的数据交换以消息为单位,用户直接利用系统提供的一组通信命令(原语)来实现通信。
c. 管道通信:管道是一条在进程间以字节流方式传送的通信通道。
它由OS 核心的缓冲区(通 常几十KB)来实现,是单向的;在实质上,是一个有OS 维护的特殊共享文件,常用于命令行所指定的输入输出重定向和管道命令。
C++ 命名管道双向通信原理一、概述C++ 是一种功能强大的编程语言,具有广泛的应用领域。
在软件开发中,双向通信是一项非常重要的功能,而命名管道是一种实现双向通信的方法之一。
本文将介绍 C++ 中命名管道的双向通信原理。
二、命名管道概述命名管道是一种特殊类型的管道,允许进程间进行双向通信。
与匿名管道不同,命名管道是通过文件系统中的特殊文件来实现通信的。
在C++ 中,可以使用一些系统调用和标准库函数来创建和操作命名管道。
三、命名管道的创建1. 首先通过系统调用 mkfifo 来创建一个命名管道文件,该函数的原型为:int mkfifo(const char *pathname, mode_t mode);其中,pathname 是指定的管道文件名,mode 是文件的权限标志。
2. 创建成功后,就可以通过标准库函数 open 来打开管道文件,并获得文件描述符:int open(const char *pathname, int flags);四、命名管道的通信1. 读写管道通过文件描述符,可以使用 read 和 write 函数来进行数据的读写操作:ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);2. 双向通信针对双向通信,可以创建两个命名管道来实现双向通信。
一个作为输入通道,一个作为输出通道,通过这两个通道可以实现双向通信的目的。
五、命名管道的同步1. 使用锁在进行命名管道的读写操作时,需要进行同步操作,可以使用互斥锁来保证多个进程之间的操作不会出现竞态条件。
2. 信号另一种同步的方式是使用信号,可以通过信号来唤醒进程,通知其进行读写操作。
六、命名管道的应用场景命名管道在实际的软件开发中具有很广泛的应用场景,例如多进程间的通信、客户端和服务器之间的通信等。
一、创建应用工程1、创建单文档应用工程2、添加新单文档应用工程二、编辑菜单项1、编辑Thread工程之菜单项2、编辑Child工程之菜单项三、添加变量、函数1、添加变量a、为CThreadView类添加变量b、为CChildView类添加变量2、添加函数a、为CThreadView类添加菜单消息响应函数b、为CChildView类添加菜单消息响应函数四、添加代码1、为CThreadView类添加代码a、添加初始化代码CThreadView::CThreadView(){// TODO: add construction code herepipe=NULL;}CThreadView::~CThreadView(){if(pipe)CloseHandle(pipe);}b、添加消息响应函数代码void CThreadView::OnPipeCreate(){// TODO: Add your command handler code herepipe=CreateNamedPipe("\\\\.\\pipe\\mypipe",PIPE_ACCESS_DUPLEX|FILE_F LAG_OVERLAPPED,0,1,1024,1024,0,NULL);if(INVALID_HANDLE_VALUE==pipe){MessageBox("管道创建失败");pipe=NULL;return;}HANDLE event;event=CreateEvent(NULL,TRUE,FALSE,NULL);if(!event){MessageBox("事件对象创建失败");CloseHandle(pipe);pipe=NULL;return;}OVERLAPPED overlap;ZeroMemory(&overlap,sizeof(OVERLAPPED));overlap.hEvent=event;ConnectNamedPipe(pipe,&overlap);//等待客户端连接WaitForSingleObject(event,INFINITE);}void CThreadView::OnPipeRead(){// TODO: Add your command handler code herechar readbuf[100];DWORD dwread;ReadFile(pipe,readbuf,100,&dwread,NULL);MessageBox(readbuf);}void CThreadView::OnPipeWrite(){// TODO: Add your command handler code herechar buf[]="你好,长江!";DWORD dwwrite;WriteFile(pipe,buf,strlen(buf)+1,&dwwrite,NULL);}2、为CChildView类添加代码a、添加初始化代码CChildView::CChildView(){// TODO: add construction code herepipe=NULL;}CChildView::~CChildView(){if(pipe)CloseHandle(pipe);}b、添加消息响应函数代码void CChildView::OnConnect(){// TODO: Add your command handler code hereWaitNamedPipe("\\\\.\\pipe\\mypipe",NMPWAIT_WAIT_FOREVER);pipe=CreateFile"\\\\.\\pipe\\mypipe",GENERIC_READ|GENERIC_WRITE,0,NU LL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);}void CChildView::OnRead(){// TODO: Add your command handler code herechar readbuf[100];DWORD dwread;ReadFile(pipe,readbuf,100,&dwread,NULL);MessageBox(readbuf);}void CChildView::OnWrite(){// TODO: Add your command handler code herechar buf[]="你好,黄河!";DWORD dwwrite;WriteFile(pipe,buf,strlen(buf)+1,&dwwrite,NULL);}五、编译六、运行七、函数说明1、CreateNamedPipe()函数声明HANDLE CreateNamedPipe(LPCTSTR lpName,DWORD dwOpenmode,DWORD dwPi peMode,DWPRD mMaxInstances,DWORD nOutBufferSize,DWORD nInbufferSiz e,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes)功能:创建一命名管道实例。
使⽤管道完成进程间通信(匿名管道pipe、命名管道fifo)每⼀个进程来说这个进程看到属于它的⼀块内存资源,这块资源是它所独占的,所以进程之间的通信就会⽐较⿇烦,原理就是需要让不同的进程间能够看到⼀份公共的资源。
所以交换数据必须通过内核,在内核中开辟⼀块缓冲区,进程1把数据从⽤户空间 拷到内核缓冲区,进程2再从内核缓冲区把数据读⾛,内核提供的这种机制称为进程间通信。
⼀般我们采⽤的进程间通信⽅式有:管道(pipe)和有名管道(FIFO)信号(signal)消息队列共享内存信号量套接字(socket)我们先来从最简单的通信⽅式来说起。
匿名管道也简称管道,管道的创建管道是⼀种最基本的进程间通信机制。
管道由pipe函数来创建:SYNOPSIS#include <unistd.h>int pipe(int pipefd[2]);调⽤pipe函数,会在内核中开辟出⼀块缓冲区⽤来进⾏进程间通信,这块缓冲区称为管道,它有⼀个读端和⼀个写端。
pipe函数接受⼀个参数,是包含两个整数的数组,如果调⽤成功,会通过pipefd[2]传出给⽤户程序两个⽂件描述符,需要注意pipefd [0]指向管道的读端, pipefd [1]指向管道的写端,那么此时这个管道对于⽤户程序就是⼀个⽂件,可以通过read(pipefd [0]);或者write(pipefd [1])进⾏操作。
pipe函数调⽤成功返回0,否则返回-1..那么再来看看通过管道进⾏通信的步骤:1.⽗进程创建管道,得到两个⽂件描述符指向管道的两端2. 利⽤fork函数创建⼦进程,则⼦进程也得到两个⽂件描述符指向同⼀管道3. ⽗进程关闭读端(pipe[0]),⼦进程关闭写端(pipe[1]),则此时⽗进程可以往管道中进⾏写操作,⼦进程可以从管道中读,从⽽实现了通过管道的进程间通信。
#include<stdio.h>#include<unistd.h>#include<string.h>int main(){int _pipe[2];int ret = pipe(_pipe);if(ret < 0){perror("pipe\n");}pid_t id = fork();if(id < 0){perror("fork\n");}else if(id == 0){close(_pipe[0]);int i = 0;char* msg = NULL;while(i < 100){msg = "I am child";write(_pipe[1], msg, strlen(msg));sleep(1);++i;}}else{close(_pipe[1]);int i = 0;char msg[100];while(i < 100){memset(msg, '\0', sizeof(msg));read(_pipe[0], msg, sizeof(msg));printf("%s\n", msg);++i;}}return0;}pipe的特点:1. 只能单向通信2. 只能⾎缘关系的进程进⾏通信(⽗⼦进程、兄弟进程)3. 依赖于⽂件系统4. ⽣命周期随进程(在内存中,进程结束被释放)5. ⾯向字节流的服务6. 管道内部提供了同步机制(锁、等待队列、信号)说明:因为管道通信是单向的,在上⾯的例⼦中我们是通过⼦进程写⽗进程来读,如果想要同时⽗进程写⽽⼦进程来读,就需要再打开另外的管道;管道的读写端通过打开的⽂件描述符来传递,因此要通信的两个进程必须从它们的公共祖先那⾥继承管道的件描述符。
C++和C#进程之间通过命名管道通信“命名管道”是一种简单的进程间通信(IPC)机制。
命名管道可在同一台计算机的不同进程之间,或在跨越一个网络的不同计算机的不同进程之间,支持可靠的、单向或双向的数据通信。
用命名管道来设计应用程序实际非常简单,并不需要事先深入掌握基层网络传送协议(如TCP/IP或IPX)的知识。
因为命名管道利用了微软网络提供者(MSNP)重定向器,通过一个网络,在各进程间建立通信。
这样一来,应用程序便不必关心网络协议的细节。
命令管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统”(NamedPipeFileSystem,NPFS)接口。
因此,客户机和服务器应用可利用标准的Win32文件系统API函数(如ReadFile和WriteFile)来进行数据的收发。
通过这些API函数,应用程序便可直接利用Win32文件系统命名规范,以及WindowsNT/Windows2000文件系统的安全机制。
NPFS依赖于MSNP重定向器在网上进行命名管道数据的发送和接收。
这样一来,便可实现接口的“与协议无关”特性:若在自己开发的应用程序中使用命名管道在网上不同的进程间建立通信,程序员不必关心基层网络传送协议(如TCP和IPX等等)的细节。
客户机和服务器命名管道最大的特点便是建立一个简单的客户机/服务器程序设计体系。
在这个体系结构中,在客户机与服务器之间,数据既可单向传递,亦可双向流动。
对命名管道服务器和客户机来说,两者的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。
对一个客户机应用来说,它只能同一个现成的命名管道服务器建立连接。
在客户机应用和服务器应用之间,一旦建好连接,两个进程都能对标准的Win32函数,在管道上进行数据的读取与写入。
这些函数包括ReadFile和WriteFile等等。
服务器要想实现一个命名管道服务器,要求必须开发一个应用程序,通过它创建命名管道的一个或多个“实例”,再由客户机进行访问。
大学实验报告学院:计信学院专业:网络工程092班级:姓名学号实验组实验时间2011-11-24指导教师成绩实验项目名实验四进程的管道通信实验称实1、了解什么是管道验2、熟悉 UNIX/LINUX支持的管道通信方式目的实1、了解什么是管道验2、熟悉 UNIX/LINUX支持的管道通信方式要求实验利用 linux下的vi编辑器及GCC编辑工具完成实验原理实验PC机器 linux操作系统仪器实编写程序实现进程的管道通信。
用系统调用pipe( )建立一管道,二个子进程P1 和P2分别向管道各写一句话:验Child 1 is sending a message!Child 2 is sending a message!P1,后 P2)。
步父进程从管道中读出二个来自子进程的信息并显示(要求先接收骤程序部分:#include <unistd.h>#include <signal.h>#include <stdio.h>int pid1,pid2;main( ){int fd[2];char outpipe[100],inpipe[100];pipe(fd);/* 创建一个管道*/while ((pid1=fork( ))==-1);if(pid1= =0){lockf(fd[1],1,0);sprintf(outpipe,"child 1 process is sending message!");/* 把串放入数组outpipe 中*/write(fd[1],outpipe,50);/* 向管道写长为 50 字节的串 */sleep(5);/* 自我阻塞 5 秒 */实lockf(fd[1],0,0);验exit(0); }内else{容while((pid2=fork( ))==-1);if(pid2= =0){lockf(fd[1],1,0);/* 互斥 */sprintf(outpipe,"child 2 process is sending message!");write(fd[1],outpipe,50);sleep(5);lockf(fd[1],0,0);exit(0);}else{wait(0);read(fd[0],inpipe,50);/* 同步 *//* 从管道中读长为50 字节的串*/ printf("%s\n",inpipe);wait(0);read(fd[0],inpipe,50);printf("%s\n",inpipe);exit(0);}}}实验数据实1、程序中的 sleep(5)起什么作用?自我阻塞 5 秒。
学生姓名:张鹏学号:150705040实验地点:数计学院407实验室实验课时:3学时实验器材:计算机课程名称:计算机操作系统实验名称:2.4实验四:使用命名管道实现进程通信一、实验目的1、进一步掌握windows系统环境下进程通信机制。
2、熟悉进程通信API二、实验环境及工具Windows 7 操作系统,VC6三、实验内容使用Windows系统提供的命名管道完成两个进程之间的通信,要求能正确使用创建命名管道CreateNamePipe()、连接命名管道ConnectNamePipe()、拆除命名管道的连接DisconnectNamePipe()、连接服务器已建立的命名管道CallNamePipe()、等待命名管道WaitNamePipe()等API.四、实验步骤服务端// PipeServer.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "PipeServer.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// The one and only application objectCWinApp theApp;using namespace std;int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){int nRetCode = 0;int err;BOOL rc;HANDLE hPipeHandle1;char lpName[]="\\\\.\\pipe\\myPipe";char InBuffer[50]="";char OutBuffer[50]="";DWORD BytesRead,BytesWrite;hPipeHandle1=CreateNamedPipe((LPCTSTR)lpName,PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED|WRITE_DAC,PIPE_TYPE_MESSAGE|PIPE_READMODE_BYTE|PIPE_W AIT,1,20,30,NMPWAIT_USE_DEFAULT_WAIT,(LPSECURITY_A TTRIBUTES)NULL);if((hPipeHandle1==INV ALID_HANDLE_V ALUE)||(hPipeHandle1==NULL)){err=GetLastError();printf("Server Pipe Creat Fail!err=%d\n",err);exit(1);}else printf("Server Pipe Creat Success!\n");while(1){rc=ConnectNamedPipe(hPipeHandle1,(LPOVERLAPPED)NULL);if(rc==0){err=GetLastError();printf("Server Pipe Connect Fail err=%d\n",err);exit(2);}else printf("Server Pipe Connect Success\n");strcpy(InBuffer,"");strcpy(OutBuffer,"");rc=ReadFile(hPipeHandle1,InBuffer,sizeof(InBuffer),&BytesRead,(LPOVERLAPPED)NULL);if(rc==0&&BytesRead==0){err=GetLastError();printf("Server Read Pipe Fail err=%d\n",err);exit(3);}else{printf("Server Read Pipe Success!\nDA TA from Client is=%s\n",InBuffer);}rc=strcmp(InBuffer,"end");if(rc==0) printf("Server Write Pipe Fail!\n");else printf("Server Write Pipe Success!\n");DisconnectNamedPipe(hPipeHandle1);rc=strcmp(OutBuffer,"end");if(rc==0) break;}printf("Now Server be END!\n");CloseHandle(hPipeHandle1);/* // initialize MFC and print and error on failureif (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)){// TODO: change error code to suit your needscerr << _T("Fatal Error: MFC initialization failed") << endl;nRetCode = 1;}else{// TODO: code your application's behavior here.CString strHello;strHello.LoadString(IDS_HELLO);cout << (LPCTSTR)strHello << endl;}*/return nRetCode;}客户端// PipeClient.cpp : Defines the entry point for the console application.#include "stdafx.h"#include "PipeClient.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif///////////////////////////////////////////////////////////////////// ////////// The one and only application objectCWinApp theApp;using namespace std;int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){BOOL rc=0;char lpName[]="\\\\.\\pipe\\myPipe";char InBuffer[50]="";char OutBuffer[50]="";DWORD BytesRead;int nRetCode = 0; int err=0;while(1){strcpy(InBuffer,"");strcpy(OutBuffer,"");printf("Input Data Please!\n");scanf("%s",InBuffer);rc=strcmp(InBuffer,"end");// initialize MFC and print and error on failureif (rc==0){rc=CallNamedPipe(lpName,InBuffer,sizeof(InBuffer),OutBuffer,sizeof(Ou tBuffer),&BytesRead,NMPWAIT_USE_DEFAULT_WAIT);break;}rc=WaitNamedPipe(lpName,NMPWAIT_WAIT_FOREVER);if(rc==0)err=GetLastError();printf("Wait Pipe Fail!err=%d\n",err);exit(1);}else printf("Wait Pipe Success!\n");rc=CallNamedPipe(lpName,InBuffer,sizeof(InBuffer),OutBuffer,sizeof(Ou tBuffer),&BytesRead,NMPWAIT_USE_DEFAULT_WAIT);rc=strcmp(OutBuffer,"end");if(rc==0)break;if(rc==0){err=GetLastError();printf("Pipe Call Fail!err=%d\n",err);exit(1);}else printf("Pipe Call Success!\nData from Server is %s\n",Out Buffer);}printf("Now Client to be End!\n");return nRetCode;}五、实验结论Windows进程通信工具有管道Pipe、共享内存、文件映射等,其中管道通信是拥有两个端点通信句柄的进程间的通信方式。
分为单向和双向。
单向是指一个端点写,另一个端点读。
管道分为匿名管道和命名管道。
匿名管道适用于父进程和子进程、两个子进程之间。
匿名管道不能在网上和不相关进程间使用。
命名管道适用于不相关的进程和不同计算机之间。
命名管道在网络上同时和多个管道通信会困难许多。