[Windows进程间通信]邮件槽(mail slot)


邮件槽(mailslot)是一种不可靠的、可广播的IPC方式。它具有以下特点

1. 不局限于本机进程间通信,可以跨设备

2. 使用无需确认的报文在网络上传输,因此不可靠,可能丢失

3. 能传输的消息大小最大为424字节

4. 可以进行广播

命名管道也是一种可以跨设备的进程间通信方式,而且可以保证数据能被正确接收,邮件槽虽然不可靠,但是可以支持广播。在同一个域内,如果有多个设备拥有同一个邮件槽名字的句柄,那么当向这个邮件槽发送消息时,所有的设备都能接收到消息。需要注意的是,同一个设备上,只能有一个server进程拥有同名邮件槽,比如,如果同一个设备上有两个进程想同时用一个邮件槽收到消息则不行。

关于邮件槽的命名:

1. 本机使用:"\\\\.\\mailslot\\[path\\]name"

2. 域内使用:"\\\\DomainName\\mailslot\\[path\\]name"

具体请参考微软官方文档:Mailslot Names - Win32 apps | Microsoft Docs

下面是本地程序使用邮件槽的例程:

Server

#include 
#include 
using namespace std;

#define MAILSLOT_NAME "\\\\.\\mailslot\\MyMailslot"
#define BUFFER_SIZE 0x100

int main() {
    char buffer[BUFFER_SIZE] = { 0 };
    DWORD dwLen = 0;
    auto hMailslot = CreateMailslot(
        MAILSLOT_NAME, 
        0, 
        MAILSLOT_WAIT_FOREVER, 
        NULL);
    if (hMailslot == INVALID_HANDLE_VALUE) {
        if (hMailslot == INVALID_HANDLE_VALUE) {
            cout << "Create mailslot failed." << endl;
            return -1;
        }
    }

    while (true) {
        auto book = ReadFile(hMailslot, buffer, BUFFER_SIZE, &dwLen, NULL);
        if (!strcmp(buffer, "quit")) {
            break;
        }
        cout << "Client: " << buffer << endl;
    }

    CloseHandle(hMailslot);

    return 0;
}

Client

#include 
#include 
using namespace std;

#define MAILSLOT_NAME "\\\\.\\mailslot\\MyMailslot"
#define BUFFER_SIZE 0x100

int main() {
    char buffer[BUFFER_SIZE] = {0};
    DWORD dwLen = 0;
    auto hMailslot = CreateFile(
        MAILSLOT_NAME, 
        GENERIC_WRITE, 
        FILE_SHARE_READ, 
        NULL, 
        CREATE_ALWAYS, 
        FILE_ATTRIBUTE_NORMAL, 
        NULL);
    if (hMailslot == INVALID_HANDLE_VALUE) {
        cout << "Can't create file." << endl;
        return -1;
    }

    while (true) {
        cin >> buffer;
        if (!strcmp(buffer, "quit")) {
            WriteFile(hMailslot, buffer, BUFFER_SIZE, &dwLen, NULL);
            break;
        }

        auto ret = WriteFile(hMailslot, buffer, BUFFER_SIZE, &dwLen, NULL);
        if (!ret) {
            CloseHandle(hMailslot);
            return -1;
        }
    }

    CloseHandle(hMailslot);

    return 0;
}