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

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

 HANDLE WINAPI CreateMailslot(
_In_ LPCTSTR lpName,
_In_ DWORD nMaxMessageSize,
_In_ DWORD lReadTimeout,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

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

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

 HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);

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

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

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

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

 BOOL WINAPI ReadFile(
_In_ HANDLE hFile,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfBytesToRead,
_Out_opt_ LPDWORD lpNumberOfBytesRead,
_Inout_opt_ LPOVERLAPPED lpOverlapped
); BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);

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

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

  服务器端:

 //header.h
#ifndef HEADER_H
#define HEADER_H #include <windows.h> #define BUFFER_SIZE 1024 class MailServer
{
public:
MailServer();
MailServer(const MailServer &) = delete;
MailServer & operator=(const MailServer &) = delete;
~MailServer();
void ReadMail();
private:
HANDLE h_mail;
char buffer[BUFFER_SIZE];
DWORD exact_read_num; //指向实际读取的字节数的指针
}; #endif
 //definition.cpp
#include "header.h"
#include <iostream> MailServer::MailServer()
{
//邮槽的命名格式为"\\.\mailslot\YourMailslotName",反斜杠需要转义,采用非阻塞式读取方法
h_mail = ::CreateMailslot("\\\\.\\mailslot\\MyMailSlot", , , nullptr);
if (h_mail == INVALID_HANDLE_VALUE)
{
std::cerr << "Failed to create a mailslot!\n";
::system("pause");
exit();
}
else
{
std::cout << "Mailslot created successfully..." << std::endl;
}
} MailServer::~MailServer()
{
::CloseHandle(h_mail);
std::cout << "Mailslot closed..." << std::endl;
} void MailServer::ReadMail()
{
std::cout << "Reading mail from mailslot..." << std::endl;
while (true)
{
if (::ReadFile(h_mail, buffer, BUFFER_SIZE, &exact_read_num, nullptr))
{
std::cout << "New mail: " << buffer << std::endl;
}
}
}
 //server.cpp
#include "header.h" int main()
{
MailServer mail_svr;
mail_svr.ReadMail();
system("pause");
return ;
}

  客户端:

 //header.h
#ifndef HEADER_H
#define HEADER_H #include "windows.h" #define BUFFER_SIZE 1024 class MailClient
{
public:
MailClient();
MailClient(const MailClient &) = delete;
MailClient & operator=(const MailClient &) = delete;
~MailClient();
void SendMail();
private:
HANDLE h_mail;
char buffer[BUFFER_SIZE];
DWORD exact_write_num;
}; #endif
 //definition.cpp
#include "header.h"
#include <iostream> MailClient::MailClient()
{
h_mail = ::CreateFile("\\\\.\\mailslot\\MyMailSlot", GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h_mail == INVALID_HANDLE_VALUE)
{
std::cerr << "Failed to create a mailslot!\n";
system("pause");
exit();
}
else
{
std::cout << "Mailslot created successfully..." << std::endl;
}
} MailClient::~MailClient()
{
::CloseHandle(h_mail);
std::cout << "Mailslot closed..." << std::endl;
} void MailClient::SendMail()
{
while (true)
{
std::cout << "Please write a mail: " << std::flush;
std::cin.getline(buffer, BUFFER_SIZE);
if (strcmp(buffer, "exit") == )
{
std::cout << "User requests to close the mailslot..." << std::endl;
break;
}
else
{
if (::WriteFile(h_mail, buffer, BUFFER_SIZE, &exact_write_num, nullptr))
{
std::cout << "Mail sent successfully..." << std::endl;
}
else
{
std::cerr << "Failed to send the mail...\n";
system("pause");
exit();
}
}
}
}
 #include "header.h"

 int main()
{
MailClient mail_clt;
mail_clt.SendMail();
system("pause");
return ;
}
05-11 09:36