zoukankan      html  css  js  c++  java
  • 利用命名管道实现进程间的通信

    常规的管道只能连接相关进程,由进程创建并由最后一个进程关闭。

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

    命名管道是建立在实际的磁盘介质或文件系统(而不是只存在内存中),任何进程可以通过文件名或路径建立与该文件的联系,命名换到需要一种FIFO文件(有先进先出的原则),虽然FIFO文件的inode节点在磁盘上,但仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。它是个FIFO先进先出队列,即使没有进程,命名管道依然可以存在,它不依赖于进程。服务器将字节写入队列,客户端从队列头部移出字节。服务器必须重写数据。它没有竞争的问题,在没有超过管道最大长度的时候,read和write都是原子操作,先将管道清空,然后再将管道写满,在读者和写者联通之前系统内核将进程挂起。FIFO是增强型的管道,适合传递较小的消息,FIFO实际相当于内核内部实现的一个共享文件。

    命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。将命名管道作为一种网络编程方案时,它实际上建立了一个客户机/服务器通信体系,并在其中可靠地传输数据。创建时可以指定哪一种用户可以访问管道,不需要用户身份验证,能够可靠地传输数据。

    命名管道服务器端和客户端的区别在于:服务器端是唯一一个有权创建命名管道的进程,也只有它才能接受命名管道客户端的连接请求。而客户端只能与一个现成的命名管道服务器建立连接。

    命名管道提供各了两种基本通信模式:字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式,在客户端和服务器端之间流动。而在消息模式中,客户端和服务器端则通过一系列不连续的数据单位,进行数据的收发,每次在管道上发出了一条消息后,它必须作为一条完整的消息读入。

    一般不用匿名管道做进程通信,推荐使用命名管道FIFO。和socket相比,不占用端口号,虽然也支持不同机器通信,但一般只用于本机进程通信,支持数据双向或单向传输。

     

    服务器端

     1     HANDLE hPipe;
     2     //创建命名管道
     3     hPipe= CreateNamedPipe("\\.\pipe\FileMonitor", 
     4         PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 
     5         0, 1, 1024, 1024, 0, NULL);
     6     if(INVALID_HANDLE_VALUE == hPipe)
     7     {
     8         AfxMessageBox("创建命名管道失败!");
     9         hPipe = NULL;
    10         return 0;
    11     }
    12     //创建事件对象
    13     HANDLE hEvent;
    14     hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    15     if(!hEvent)
    16     {
    17         AfxMessageBox("创建事件对象失败!");
    18         CloseHandle(hPipe);
    19         hPipe = NULL;
    20         return 0;
    21     }
    22     //等待客户端连接
    23     OVERLAPPED ovlap;
    24     ZeroMemory(&ovlap, sizeof(OVERLAPPED));
    25     ovlap.hEvent = hEvent;
    26     if(!ConnectNamedPipe(hPipe, &ovlap))
    27     {
    28         if(ERROR_IO_PENDING != GetLastError())
    29         {
    30             AfxMessageBox("等待客户端连接失败!");
    31             CloseHandle(hPipe);
    32             CloseHandle(hEvent);
    33             hPipe = NULL;
    34             return 0;
    35         }
    36     }
    37     //等待失败
    38     if(WAIT_FAILED == WaitForSingleObject(hEvent, INFINITE))
    39     {
    40         AfxMessageBox("等待对象失败!");
    41         CloseHandle(hPipe);
    42         CloseHandle(hEvent);
    43         hPipe = NULL;
    44         return 0;
    45     }
    46     CloseHandle(hEvent);
    47     const int nBufferLen = 256;  
    48     char cRecvMsg[nBufferLen];
    49     char cSendMsg[nBufferLen];  
    50     DWORD dwLen;  
    51 
    52     //接收客户端发送的数据  
    53     ReadFile(hPipe, cRecvMsg, nBufferLen, &dwLen, NULL);//读取管道中的内容(管道是一种特殊的文件)
    54     MessageBox(cRecvMsg);
    55 
    56     //确认已收到数据  
    57     strcpy(cSendMsg, "1");  
    58     WriteFile(hPipe, cSendMsg, strlen(cSendMsg) + 1, &dwLen, NULL);   
    59 
    60     DisconnectNamedPipe(hPipe);   
    61     CloseHandle(hPipe);//关闭管道
    62     hPipe = NULL;

    客户端

     1     //等待连接命名管道
     2     if(!WaitNamedPipe("\\.\pipe\FileMonitor", NMPWAIT_WAIT_FOREVER))
     3     {
     4         AfxMessageBox("当前没有可利用的命名管道示例!");
     5         return 0;
     6     }
     7     //打开命名管道
     8     HANDLE hPipe;
     9     hPipe= CreateFile("\\.\pipe\FileMonitor", GENERIC_READ | GENERIC_WRITE, 
    10         0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    11     if(INVALID_HANDLE_VALUE == hPipe)
    12     {
    13         AfxMessageBox("打开命名管道失败!");
    14         hPipe = NULL;
    15         return 0;
    16     }
    17     //开始传递信息
    18     DWORD dwLen;
    19     const int nBufferLen = 256;
    20     char cRecvMsg[nBufferLen];
    21     char cSendMsg[nBufferLen];
    22     CString strSendMsg = "";
    23 
    24     //向客户端发送数据
    25     strSendMsg = "发送的数据";
    26             
    27     if(strSendMsg == "")
    28     {
    29         AfxMessageBox("空字符串,不能发送!");
    30         return 0;
    31     }
    32     strcpy(cSendMsg, strSendMsg);  
    33     WriteFile(hPipe, cSendMsg, strlen(cSendMsg) + 1, &dwLen, NULL);       
    34     //接收客户端反馈的数据  
    35     ReadFile(hPipe, cRecvMsg, nBufferLen, &dwLen, NULL);  //读取管道中的内容(管道是一种特殊的文件)
     
  • 相关阅读:
    flask之闪现
    对于Flask中蓝图的理解
    flask中的CBV和FBV
    Flask之基本使用与配置
    Flask
    Flask-信号(blinker)
    flask-migrate
    Flask WTForms的使用和源码分析 —— (7)
    mac下卸载jdk
    RabbitMQ五种消息队列学习(三)–Work模式
  • 原文地址:https://www.cnblogs.com/zerotoinfinity/p/6405066.html
Copyright © 2011-2022 走看看