您的位置:首页 > 编程语言 > C语言/C++

c++下使用邮槽实现进程间通信

2016-02-16 14:33 639 查看
  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", 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: