c++下使用郵槽實現進程間通訊

  Windows API提供了郵槽和命名管道兩種機制來實現進程間通訊,在這裏使用C++實現郵槽。ios

  郵槽是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表示郵槽的名稱。郵槽名稱的格式爲"\\.\mailslot\YourMailslotName",其中YourMailslotName由用戶指定。須要注意的是,在實際編碼中反斜槓須要轉義;參數nMaxMessageSize表示發送的消息大小的最大值,若設置爲0則表示大小爲任意值。(實際上郵槽能傳輸的數據很是小,通常400KB,若數據過大,郵槽可能沒法正常工做);參數lReadTimeout表示讀取操做的超時時間;參數lpSecurityAttributes表示郵槽的安全屬性,置爲NULL表示使用默認的安全屬性。windows

  客戶端在使用郵槽前必須先打開郵槽,經過函數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 網絡

  須要注意的是,指定要打開的郵槽時,若程序是在不一樣主機上運行的,郵槽名稱中的點號"."須要改爲對方主機的名稱。app

  在實際的編程過程當中,對郵槽的操做與文件同樣,都是經過調用函數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類型的指針,表示實際讀取/寫入的字節數。編碼

  最終實現的代碼以下,實現面向對象的方法實現:spa

  服務器端:

 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     //郵槽的命名格式爲"\\.\mailslot\YourMailslotName",反斜槓須要轉義,採用非阻塞式讀取方法
 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!\n";
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!\n";
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...\n";
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 }
相關文章
相關標籤/搜索