zoukankan      html  css  js  c++  java
  • c++下使用邮槽实现进程间通信

      Windows API提供了邮槽和命名管道两种机制来实现进程间通信,在这里使用C++实现邮槽。

      邮槽是Windows提供的一种进程间单向通信的机制,进程中的一方只能读取(或写入)数据,而另一方只能写入(或读取)数据。这种进程间的通信可以发生在本地或者网络之中。而在使用邮槽之前,服务器端必须先创建邮槽,创建的函数原型如下:

    1 HANDLE WINAPI CreateMailslot(
    2   _In_     LPCTSTR               lpName,
    3   _In_     DWORD                 nMaxMessageSize,
    4   _In_     DWORD                 lReadTimeout,
    5   _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
    6 );

      其中参数lpName表示邮槽的名称。邮槽名称的格式为"\.mailslotYourMailslotName",其中YourMailslotName由用户指定。需要注意的是,在实际编码中反斜杠需要转义;参数nMaxMessageSize表示发送的消息大小的最大值,若设置为0则表示大小为任意值。(实际上邮槽能传输的数据非常小,一般400KB,若数据过大,邮槽可能无法正常工作);参数lReadTimeout表示读取操作的超时时间;参数lpSecurityAttributes表示邮槽的安全属性,置为NULL表示使用默认的安全属性。

      客户端在使用邮槽前必须先打开邮槽,通过函数CreateFile()实现,函数原型如下:

    1 HANDLE WINAPI CreateFile(
    2   _In_     LPCTSTR               lpFileName,
    3   _In_     DWORD                 dwDesiredAccess,
    4   _In_     DWORD                 dwShareMode,
    5   _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    6   _In_     DWORD                 dwCreationDisposition,
    7   _In_     DWORD                 dwFlagsAndAttributes,
    8   _In_opt_ HANDLE                hTemplateFile
    9 );

      参数的具体设置方法可参考MSDN给出的解释:

      https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 

      需要注意的是,指定要打开的邮槽时,若程序是在不同主机上运行的,邮槽名称中的点号"."需要改成对方主机的名称。

      在实际的编程过程中,对邮槽的操作与文件一样,都是通过调用函数ReadFile()和WriteFile()实现的,函数原型如下:

     1 BOOL WINAPI ReadFile(
     2   _In_        HANDLE       hFile,
     3   _Out_       LPVOID       lpBuffer,
     4   _In_        DWORD        nNumberOfBytesToRead,
     5   _Out_opt_   LPDWORD      lpNumberOfBytesRead,
     6   _Inout_opt_ LPOVERLAPPED lpOverlapped
     7 );
     8 
     9 BOOL WINAPI WriteFile(
    10   _In_        HANDLE       hFile,
    11   _In_        LPCVOID      lpBuffer,
    12   _In_        DWORD        nNumberOfBytesToWrite,
    13   _Out_opt_   LPDWORD      lpNumberOfBytesWritten,
    14   _Inout_opt_ LPOVERLAPPED lpOverlapped
    15 );

      其中参数lpNumberOfBytesWritten是一个指向DWORD类型的指针,表示实际读取/写入的字节数。

      最终实现的代码如下,实现面向对象的方法实现:

      服务器端:

     1 //header.h
     2 #ifndef HEADER_H
     3 #define HEADER_H
     4 
     5 #include <windows.h>
     6 
     7 #define BUFFER_SIZE 1024
     8 
     9 class MailServer
    10 {
    11 public:
    12     MailServer();
    13     MailServer(const MailServer &) = delete;
    14     MailServer & operator=(const MailServer &) = delete;
    15     ~MailServer();
    16     void ReadMail();
    17 private:
    18     HANDLE h_mail;
    19     char buffer[BUFFER_SIZE];
    20     DWORD exact_read_num; //指向实际读取的字节数的指针
    21 };
    22 
    23 #endif
     1 //definition.cpp
     2 #include "header.h"
     3 #include <iostream>
     4 
     5 MailServer::MailServer()
     6 {
     7     //邮槽的命名格式为"\.mailslotYourMailslotName",反斜杠需要转义,采用非阻塞式读取方法
     8     h_mail = ::CreateMailslot("\\.\mailslot\MyMailSlot", 0, 0, nullptr);
     9     if (h_mail == INVALID_HANDLE_VALUE)
    10     {
    11         std::cerr << "Failed to create a mailslot!
    ";
    12         ::system("pause");
    13         exit(1);
    14     }
    15     else
    16     {
    17         std::cout << "Mailslot created successfully..." << std::endl;
    18     }
    19 }
    20 
    21 MailServer::~MailServer()
    22 {
    23     ::CloseHandle(h_mail);
    24     std::cout << "Mailslot closed..." << std::endl;
    25 }
    26 
    27 void MailServer::ReadMail()
    28 {
    29     std::cout << "Reading mail from mailslot..." << std::endl;
    30     while (true)
    31     {
    32         if (::ReadFile(h_mail, buffer, BUFFER_SIZE, &exact_read_num, nullptr))
    33         {
    34             std::cout << "New mail: " << buffer << std::endl;
    35         }
    36     }
    37 }
     1 //server.cpp
     2 #include "header.h"
     3 
     4 int main()
     5 {
     6     MailServer mail_svr;
     7     mail_svr.ReadMail();
     8     system("pause");
     9     return 0;
    10 }

      客户端:

     1 //header.h
     2 #ifndef HEADER_H
     3 #define HEADER_H
     4 
     5 #include "windows.h"
     6 
     7 #define BUFFER_SIZE 1024
     8 
     9 class MailClient
    10 {
    11 public:
    12     MailClient();
    13     MailClient(const MailClient &) = delete;
    14     MailClient & operator=(const MailClient &) = delete;
    15     ~MailClient();
    16     void SendMail();
    17 private:
    18     HANDLE h_mail;
    19     char buffer[BUFFER_SIZE];
    20     DWORD exact_write_num;
    21 };
    22 
    23 #endif
     1 //definition.cpp
     2 #include "header.h"
     3 #include <iostream>
     4 
     5 MailClient::MailClient()
     6 {
     7     h_mail = ::CreateFile("\\.\mailslot\MyMailSlot", GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
     8     if (h_mail == INVALID_HANDLE_VALUE)
     9     {
    10         std::cerr << "Failed to create a mailslot!
    ";
    11         system("pause");
    12         exit(1);
    13     }
    14     else
    15     {
    16         std::cout << "Mailslot created successfully..." << std::endl;
    17     }
    18 }
    19 
    20 MailClient::~MailClient()
    21 {
    22     ::CloseHandle(h_mail);
    23     std::cout << "Mailslot closed..." << std::endl;
    24 }
    25 
    26 void MailClient::SendMail()
    27 {
    28     while (true)
    29     {
    30         std::cout << "Please write a mail: " << std::flush;
    31         std::cin.getline(buffer, BUFFER_SIZE);
    32         if (strcmp(buffer, "exit") == 0)
    33         {
    34             std::cout << "User requests to close the mailslot..." << std::endl;
    35             break;
    36         }
    37         else
    38         {
    39             if (::WriteFile(h_mail, buffer, BUFFER_SIZE, &exact_write_num, nullptr))
    40             {
    41                 std::cout << "Mail sent successfully..." << std::endl;
    42             }
    43             else
    44             {
    45                 std::cerr << "Failed to send the mail...
    ";
    46                 system("pause");
    47                 exit(1);
    48             }
    49         }
    50     }
    51 }
    1 #include "header.h"
    2 
    3 int main()
    4 {
    5     MailClient mail_clt;
    6     mail_clt.SendMail();
    7     system("pause");
    8     return 0;
    9 }
  • 相关阅读:
    SpringBoot入门篇--读取资源文件配置
    SpringBoot入门篇--使用Thymeleaf模板引擎进行页面的渲染
    SpringBoot入门篇--热部署
    NOI2017 游记
    BZOJ 2754 【SCOI2012】 喵星球上的点名
    codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
    BZOJ 4407 于神之怒加强版
    BZOJ 2956 模积和
    BZOJ 4584 【APIO2016】 赛艇
    BZOJ 4591 【SHOI2015】 超能粒子炮·改
  • 原文地址:https://www.cnblogs.com/jzincnblogs/p/5192654.html
Copyright © 2011-2022 走看看