【操作系统】实验四 使用命名管道实现进程通信

实验四

一、实验目的

(1)了解windows系统环境下的进程通讯机制。

(2)熟悉Windows系统提供的进程通信API。

二、实验准备

1.建立命名管道:CreateNamePipe() 创建一个命名管道实例

原型:

HANDLE CreateNamePipe(
    LPCTSTR lpName,          //命名管道的名字
    DWORD dwOpenMode,        //命名管道的访问模式
    DWORD dwPipe’Mode,        //命名管道的模式
    DWORD nMaxInstances,      //可创建实例的最大值
    DWORD nOutBufferSize,      //以字节为单位的输出缓冲区的大小
    DWORD nInBufferSize,       //以字节为单位的输入缓冲区的大小
    DWORD nDefaultTimeOut,    //默认超时时间,以ms为单位
    LPSECURITY_ATTRIBUTES lpSecurityAttributes    //安全属性
);

返回值:

如果管道创建成功,将返回服务器命名管道实例的句柄。如果失败,返回INVALID_HANDLE_VALUE,可以调用函数GetLastError()查询失败的原因;当返回ERROR_INVALID_PARAMETER时,表明参数nMaxInstances指定的值大于PIPE_UNLIMTED_INSTANCES。

2.连接命名管道(服务器):ConnectNamePipe()

创建后命名管道也等待客户端的连接,客户端可以使用函数CreateFile()和CallNamedPipe()进行连接。

原型:

BOOL ConnectNamedPipe(
HANDLE hNamePipe,          //命名管道实例句柄
LPOVERLAPPED lpOver lapped        //指向Overlapped结构的指针
);

返回值:

成功,将返回一个非0值;失败,系统返回0,可以调用函数GetLastError()查询失败的原因。

3.拆除命名管道的连接:DisconnectNamePipe()

拆除命名管道服务器与客户端的连接。

原型:

BOOL DisconnectNamePipe(
HANDLE hNamePipe     //命名管道创建时得到的一个命名管道实例句柄
);

返回值:

成功,将返回一个非0值;失败,系统返回0,可以调用函数GerLasrError()查询失败的原因。

4.客户端连接服务器已建立的命名管道(客户端):CallNamePipe()

原型:

BOOL CallNamePipe(
   LPCTSTR lpNamePipeName,       //命名管道的名字
   LPVOID lpInBuffer,            //输出数据缓冲区
   DWORD nInBufferSize,      //以字节为单位的输出数据缓冲区的大小
   LPVOID lpOurBuffer,          //输入数据缓冲区指针
   DWORD nOurBufferSize,     //以字节为单位的输入数据缓冲区的大小
   LPDWORD lpBytesRead,         //输入字节数指针,32位
   DWORD nTimeOUT               //等待时间,单位为ms
);

返回值:

成功,将返回一个非0值;失败,系统返回0,可用调用函数GetLastError()查询失败的原因。

5.客户端等待命名管道: WaitNamedPipe()

客户端使用函数等待服务器连接命名管道

原型:

BOOL WaitNamedPipe(
LPCTSTR lpNamedPipeName,         //要等待的命名管道名
DWORD nTimeOut                   //等待时间,单位为ms
);

返回值:

在等待时间内要连接的命名管道可以使用,将返回一个非0值。在等待时间内要连接的命名管道不可以使用,系统返回0,可用调用GetLastError()查询失败的原因。

三、实验内容

(一)实验内容

使用命名管道完成两个进程之间的通信。

使用Windows系统提供的命名管道完成两个进程之间的通信,要求能正确使用创建命名管道CreateNamePipe() 、连接命名管道ConnectNamePipe() 、拆除命名道的连接DisconnectNamePipe() 、连接服务器已建立的命名管道CallNamePipe() 、等待命名管道WaitNamedPipe() 等API.

(二)主要代码

服务器端:
// PipeClient.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "PipeClient.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// The one and only application object

CWinApp 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!"); 
        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_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", OutBuffer); 
    } 
    puts("Now Client to be End!"); 

	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_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// The one and only application object

CWinApp 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!"); 
        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_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", OutBuffer); 
    } 
    puts("Now Client to be End!"); 

	return nRetCode;
}

四、实验结果与总结

运行结果:

服务器端:

Server Pipe Create Success!Server Pipe Connect Success!   //客户端1
Server Read Pipe Success!
DATA from Client is = HelloServe!
Please Input Data to Send
HelloClient!
Server Write Pipe Success!
Server Pipe Connect Success!
Server Read Pipe Success!
DATA from Client is = 2HELLO
Please Input Data to SendHDDS
Server Write Pipe Success!
Server Pipe Connect Success!
Server Read Pipe Success!
DATA from Client is = DDD
Please Input Data to Send
WWW
Server Write Pipe Success!
Server Pipe Connect Success!        //客户端2
Server Read Pipe Success!
DATA from Client is = 233
Please Input Data to Send
445
Server Write Pipe Success!

在这里插入图片描述

客户端1:

Input Data Please!
HelloServe!
Wait Pipe Success!
Pipe Call Success!
Data from Server is HelloClient!
Input Data Please!
2HELLO
Wait Pipe Success!
Pipe Call Success!
Data from Server is HDDS
Input Data Please!
DDD
Wait Pipe Success!
Pipe Call Success!
Data from Server is WWW
Input Data Please!

在这里插入图片描述

客户端2:

Input Data Please!
233
Wait Pipe Success!
Pipe Call Success!
Data from Server is 445
Input Data Please!
总结:

1.命名工程名称时出现了问题,最终发现是未切换到英文输入状态的原因

2.打开左侧工作空间:菜单栏:查看→工作空间

3.在网上搜了如何同时打开两个工程,发现还是直接打开两个窗口更简单,若在一个工程的基础上再打开另一个工程,则前一个会被覆盖

4.LINK : fatal error LNK1168: cannot open Debug/PipeServe.exe for writing错误:

是由于前一次调试运行是最后没有按任意键退出程序,而是点“关闭”按钮关 cmd窗口的,**vc6.0++有bug的 ,点关闭按钮有时后会导致窗口被关闭了但是程序进程还在运行。

解决方法:

方法一.关闭该工程并新建一个新的工程。

方法二.Ctrl+Alt+Delete打开资源管理器,找到该进程并强制关闭。

5.在实验基础上新建了PipeClient2客户端,实现了多个客户端与服务器之间的通信


比较windows下进程间通信的几种方法:

1.文件映射

​ 文件映射是在多个进程间共享数据的非常有效方法,有较好的安全性。但文件映射只能用于本地机器的进程之间,不能用于网络中,而开发者还必须控制进程间的同步。

2.匿名管道

​ 匿名管道是单机上实现子进程标准I/O重定向的有效方法,它不能在网上使用,也不能用于两个不相关的进程之间。

3.命名管道

​ 命名管道(Named Pipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。不同于匿名管道的是命名管道可以在不相关的进程之间和不同计算机之间使用,服务器建立命名管道时给它指定一个名字,任何进程都可以通过该名字打开管道的另一端,根据给定的权限和服务器进程通信。
 命名管道提供了相对简单的编程接口,使通过网络传输数据并不比同一计算机上两进程之间通信更困难,不过如果要同时和多个进程通信它就力不从心了。

4.Sockets
 现在通过Sockets实现进程通信的网络应用越来越多,这主要的原因是Sockets的跨平台性要比其它IPC机制好得多,另外WinSock 2.0不仅支持TCP/IP协议,而且还支持其它协议(如IPX)。Sockets的唯一缺点是它支持的是底层通信操作,这使得在单机的进程间进行简单数据传递不太方便,这时使用下面将介绍的WM_COPYDATA消息将更合适些。

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值