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

实验四:使用命名管道实现进程通信


一、实验目的

(1)了解windows系统环境下的进程通信机制。
(2)熟悉Windows系统提供的进程通信API。
(3)熟悉掌握文件读写函数WriteFile()和ReadFile()。

二、实验准备

(1).CreateNamePipe()创建一个命名管道实例,并返回该管道的句柄。
 1.函数原型:
  HANDLE CreateNamePipe(
    LPCTSTR lpName,                     //命名管道的名字
    DWORD dwOpenMode,                 //命名管道的访问模式
    DWORD dwPipeMode,                 //命名管道的模式
    DWORD nMaxInstances,                //可创建实例的最大值
    DWORD nOutBufferSize,                //以字节为单位的输出缓冲区的大小
    DWORD nInBufferSize,                //以字节为单位的输入缓冲区的大小
    DWORD nDefaultTimeOut,               //默认超时时间
    LPSECURITY_ATTRIBUTES lpSecurityAttributes         //安全属性
    );
 2.参数说明:
  (1)lpName:为命名管道的名字,管道的命名方式为\\ServerName\pipe\pipename,其中ServerName为用命名管道通信时服务器的主机名或IP地址,pipename为命名管道的名字,用户可自行定义。
  (2)dwOpenMode:指出命名管道的访问模式。
      PIPE_ACCESS_DUPLEX	双向管道。服务器和客户都可以进行读和写
  (3)dwPipeMode:指出管道的模式。
	  PIPE_TYPE_BYTE	以字符流的方式向管道写数据。该模式下不能使用PIPE_READMODE_MESSAGE
	  PIPE_TYPE_MESSAGE	以信息流的方式向管道写数据。模式下可以使用PIPE_READMODE_MESSAGE和								PIPE_READMODE_BYTE
  (4)nMaxInstances:该命名管道可以创建实例的最大值。
  (5)nOutBufferSize:输出缓冲区的大小,以字节为单位。
  (6)nInBufferSize:输入缓冲区的大小,以字节为单位。
  (7)nDefaultTimeOut:默认的超时时间,以ms为单位。
	  如果函数WaitNamePipe()指出NMWAIT_USE_DEFAULT_WAIT,每个管道实例必须指定同一值的名字。
  (8)lpSecurityAttributes:为管道指定安全属性,为NULL时,管道得到一个默认的安全描述符。
 3.返回值:
  如果管道创建成功,将返回服务器命名管道实例的句柄。如果失败,返回INVALID_HANDLE_VALUE,可以调用函数GetLastError()查询失败的原因。
  
(2).ConnectNamePipe()连接命名管道。创建后命名管道也等待客户端的连接,客户端可以使用函数CreateFile()和									CallNamedPipe()进行连接。
 1.函数原型:
  BOOL ConnectNamedPipe(
	HANDLE hNamePipe,          		 //命名管道实例句柄
	LPOVERLAPPED lpOver lapped        //指向Overlapped结构的指针
	);
 2.参数说明:
  hNamedPipe:为命名管道创建时得到的一个命名管道实例句柄。
  lpOverlapped:指向Overlapped结构的指针,可设其为NULL。
 3.返回值:
  成功,将返回一个非0值;失败,系统返回0,可以调用函数GetLastError()查询失败的原因。

(3).DisconnecrNamePipe()拆除命名管道服务器与客户端的连接。
 1.函数原型:
  BOOL DisconnectNamePipe(
	HANDLE hNamePipe  //命名管道实例句柄
	);
 2.参数说明:
  hNamedPipe:为命名管道创建时得到的一个命名管道实例句柄。
 3.返回值:
  成功,将返回一个非0值;失败,系统返回0,可以调用函数GerLasrError()查询失败的原因。
  
(4).CallNamePipe()客户端连接服务器建立的命名管道。
 1.函数原型:
  BOOL CallNamePipe(
   LPCTSTR lpNamePipeName,           //命名管道的名字
   LPVOID lpInBuffer,                  //输出数据缓冲区
   DWORD nInBufferSize,              //以字节为单位的输出数据缓冲区的大小
   LPVOID lpOurBuffer,                //输入数据缓冲区指针
   DWORD nOurBufferSize,           //以字节为单位的输入数据缓冲区的大小
   LPDWORD lpBytesRead,              //输入字节数指针
   DWORD nTimeOUT                  //等待时间
   );
 2.参数说明:
  lpNamedPipeName:命名管道的名字。
  lpInBuffer:指出用于输出数据(向管道写数据)的缓冲区指针。
  nInBufferSize:用于输出数据缓冲区的大小,以字节为单位。
  lpOutBuffer:指出用于接收数据(从管道读出数据)的缓冲区指针。
  nOutBufferSize:指向用于接收数据缓冲区的大小,以字节为单位。
  lpBytesRead:一个32位的变量,改变量用于存储从管道读出的字节数。
  nTimeOut:等待命名管道成为可用状态的时间,单位为ms。
 3.返回值:
  成功,将返回一个非0值;失败,系统返回0,可用调用函数GetLastError()查询失败的原因。
  
(5).WairNamedPipe()客户端等待服务器连接命名管道。
 1.函数原型:
  BOOL WaitNamedPipe(
	LPCTSTR lpNamedPipeName,         //要等待的命名管道名
	DWORD nTimeOut                   //等待时间
	);
 2.参数说明:
  lpNamedPipeName:要等待的命名管道的名字。
  nTimeOut:等待命名管道成为可用状态的时间,单位为ms.
 3.返回值:
  在等待时间内要连接的命名管道可以使用,将返回一个非0值。在等待时间内要连接的命名管道不可以使用,系统返回0,可用调用GetLastError()查询失败的原因。

三、实验内容

(一)实验内容
实验:
  使用命名管道完成两个进程之间的通信。要求使用Windows系统提供的命名管道完成两个进程之间的通信,要求能正确使用创建命名管道CreateNamePipe()、连接命名管道ConnectNamePipe()、拆除命名道的连接DisconnectNamePipe()、连接服务器已建立的命名管道CallNamePipe()、等待命名管道WaitNamedPipe()等API。
(二)主要代码
服务器程序:
#include "stdafx.h"
#include "04.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[])
{
	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) || (hPipeHandle1 == NULL)) 
    { 
        err = GetLastError(); 
        printf("Server Pipe Create Fail! err = %d\n", err); 
        exit(1);  
    } 
    else
        printf("Server Pipe Create Success!"); 
          
    while(TRUE) 
    { 
        //连接命名管道  
        rc = ConnectNamedPipe(hPipeHandle1, 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(2); 
        } 
        else
            printf("Server Read Pipe Success!DATA from Client is:\n %s\n",  
            InBuffer); 
        rc = strcmp(InBuffer, "end"); 
        if (rc == 0) 
            break; 
        printf("Please Input Data to Send"); 
        scanf("%s", OutBuffer); 
        //向命名管道中写数据  
        rc = WriteFile(hPipeHandle1, OutBuffer, sizeof(OutBuffer), &BytesWrite,  
        (LPOVERLAPPED)NULL); 
        if (rc == 0) 
            puts("Server Write Pipe Fail!"); 
        else
            puts("Server Write Pipe Success!"); 
        //拆除与命名管道的连接  
        DisconnectNamedPipe(hPipeHandle1); 
        rc = strcmp(OutBuffer, "end"); 
        if (rc == 0) 
            break; 
    } 
    printf("Now Server be END!"); 
    CloseHandle(hPipeHandle1); 
    return nRetCode; 
}
客户端程序:
#include "stdafx.h"
#include "042.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; 
}

四、实验结果与总结

实验:
    分别创建两个工程,一个作为服务器端程序另一个作为客户端程序,从而实现进程之间的通信。熟练掌握了 CreateNamePipe()函数,创建一个命名管道实例。服务器用函数 ConnectNamePipe()连接命名管道。在客户端,客户端使用 CallNamePipe()函数连接服务器建立的命名管道。客户端使用 WairNamedPipe()函数等待服务器连接命名管道。

image

image

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

司马道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值