c++下使用邮槽实现进程间通信
2016-02-16 14:33
639 查看
Windows API提供了邮槽和命名管道两种机制来实现进程间通信,在这里使用C++实现邮槽。
邮槽是Windows提供的一种进程间单向通信的机制,进程中的一方只能读取(或写入)数据,而另一方只能写入(或读取)数据。这种进程间的通信可以发生在本地或者网络之中。而在使用邮槽之前,服务器端必须先创建邮槽,创建的函数原型如下:
其中参数lpName表示邮槽的名称。邮槽名称的格式为"\\.\mailslot\YourMailslotName",其中YourMailslotName由用户指定。需要注意的是,在实际编码中反斜杠需要转义;参数nMaxMessageSize表示发送的消息大小的最大值,若设置为0则表示大小为任意值。(实际上邮槽能传输的数据非常小,一般400KB,若数据过大,邮槽可能无法正常工作);参数lReadTimeout表示读取操作的超时时间;参数lpSecurityAttributes表示邮槽的安全属性,置为NULL表示使用默认的安全属性。
客户端在使用邮槽前必须先打开邮槽,通过函数CreateFile()实现,函数原型如下:
参数的具体设置方法可参考MSDN给出的解释:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
需要注意的是,指定要打开的邮槽时,若程序是在不同主机上运行的,邮槽名称中的点号"."需要改成对方主机的名称。
在实际的编程过程中,对邮槽的操作与文件一样,都是通过调用函数ReadFile()和WriteFile()实现的,函数原型如下:
其中参数lpNumberOfBytesWritten是一个指向DWORD类型的指针,表示实际读取/写入的字节数。
最终实现的代码如下,实现面向对象的方法实现:
服务器端:
客户端:
邮槽是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", 0, 0, nullptr); if (h_mail == INVALID_HANDLE_VALUE) { std::cerr << "Failed to create a mailslot!\n"; ::system("pause"); exit(1); } 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 0; }
客户端:
//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(1); } 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") == 0) { 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(1); } } } }
#include "header.h" int main() { MailClient mail_clt; mail_clt.SendMail(); system("pause"); return 0; }