• 20、Windows API 进程间通信,邮槽(Mailslot)


        进程的地址空间是私有的。出于安全性的目的,如果一个进程不具有特殊的权限,是无法访问另外一个进程的内存空间的,也无法知道内存中保存的数据的意义。但是在一些具体的应用情况下需要多个进行相互配合,有时计算机用户也需要在多个应用程序之间交换数据。

    Windows系统下,在进程间通信或共享数据的方式如下。

    ◇邮槽(Mailslot)

        邮槽是最为简单的进程间数据共享方式,一个进程创建并拥有一个邮槽,其他进程都可以打开这个邮槽并向其发送消息。

    ◇管道(Pipe)

    实质是一种共享的内存,由一个进程创建,其他进程连接,并可进行双向的通信。

    ◇剪贴板(Clipboard)

        剪贴板是重要的进程间数据共享方式,所有的进程都可以设置和修改剪贴板,也都可以从剪贴板获取内容。

    ◇消息,具体是指WM_COPYDATA消息。

    消息具有参数wParamlParam。但是wParamlParam最多是32位的。而WM_COPYDATA消息的参数不受wParamlParam数据大小的限制,可以用于在进程间传递数据。

    ◇网络。

        网络可以在不同主机上的不同程序间通信,当然也可以在相同主机上的不同程序间通信。

    FileMapping[2]

    一、邮槽(MailSlot)

        使用邮槽通信的进程分为服务端和客户端。邮槽由服务端创建,在创建时需要指定邮槽名,创建后服务端得到邮槽的句柄。在邮槽创建后,客户端可以通过邮槽名打开邮槽,在获得句柄后可以向邮槽写入消息。

        邮槽通信是单向的,只有服务端才能从邮槽中读取消息,客户端只能写入消息。消息是先入先出的。客户端先写入的消息在服务端先被读取。

    通过邮槽通信的数据可以是任意格式的,但是一条消息不能大于424字节。邮槽除了在本机内进行进程间通信外,在主机间也可以通信。但是在主机间进行邮槽通信,数据通过网络传播时使用的是数据报协议(UDP),所以是一种不可靠的通信。通过网络进行邮槽通信时,客户端必须知道服务端的主机名或域名。

    MailSlot的详细介绍,可以参见[3],[4]也作了一些介绍。

    邮槽通信服务端程序

    通过mailslot进程间通信-服务端
    通过mailslot进程间通信
    **************************************/
    /* 头文件 */
    #include
    <windows.h>
    #include
    <stdio.h>
    /* 全局变量 */
    HANDLE hSlot;
    LPTSTR lpszSlotName
    = TEXT("\\\\.\\mailslot\\sample_mailslot");
    LPTSTR Message
    = TEXT("Message for mailslot in primary domain.");

    /* ************************************
    * void main()
    * 功能 进程间mailslot通信客户端
    *************************************
    */
    void main()
    {
    DWORD cbMessage, cMessage, cbRead;
    BOOL fResult;
    LPTSTR lpszBuffer;
    TCHAR achID[
    80];
    DWORD cAllMessages;
    HANDLE hEvent;
    OVERLAPPED ov;

    cbMessage
    = cMessage = cbRead = 0;

    hSlot
    = CreateMailslot(
    lpszSlotName,
    // mailslot 名
    0, // 不限制消息大小
    MAILSLOT_WAIT_FOREVER, // 无超时
    (LPSECURITY_ATTRIBUTES) NULL);

    if (hSlot == INVALID_HANDLE_VALUE)
    {
    printf(
    "CreateMailslot failed with %d\n", GetLastError());
    return ;
    }
    else printf("Mailslot created successfully.\n");

    while(1)
    {
    // 获取mailslot信息
    fResult = GetMailslotInfo(hSlot, // mailslot 句柄
    (LPDWORD) NULL, // 无最大消息限制
    &cbMessage, // 下一条消息的大小
    &cMessage, // 消息的数量
    (LPDWORD) NULL); // 无时限

    if (!fResult)
    {
    printf(
    "GetMailslotInfo failed with %d.\n", GetLastError());
    return ;
    }

    if (cbMessage == MAILSLOT_NO_MESSAGE)
    {
    // 没有消息,过一段时间再去读
    Sleep(20000);
    continue;
    }

    cAllMessages
    = cMessage;

    while (cMessage != 0) // 获取全部消息,有可能不只一条
    {
    // 提示信息
    wsprintf((LPTSTR) achID,
    "\nMessage #%d of %d\n",
    cAllMessages
    - cMessage + 1,
    cAllMessages);

    // 分配空间
    lpszBuffer = (LPTSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
    lstrlen((LPTSTR) achID)
    *sizeof(TCHAR) + cbMessage);
    if( NULL == lpszBuffer )
    {
    return ;
    }
    // 读取消息
    fResult = ReadFile(hSlot, // mailslot句柄
    lpszBuffer, // 缓存
    cbMessage, // 消息的长度
    &cbRead, // 实际读取的长度
    NULL);

    if (!fResult)
    {
    printf(
    "ReadFile failed with %d.\n", GetLastError());
    GlobalFree((HGLOBAL) lpszBuffer);
    return ;
    }

    // 处理信息,显示
    lstrcat(lpszBuffer, (LPTSTR) achID);
    printf(
    "Contents of the mailslot: %s\n", lpszBuffer);

    HeapFree(GetProcessHeap(),
    0,lpszBuffer);
    // 计算剩余的消息数
    fResult = GetMailslotInfo(hSlot,
    (LPDWORD) NULL,
    &cbMessage,
    &cMessage,
    (LPDWORD) NULL);

    if (!fResult)
    {
    printf(
    "GetMailslotInfo failed (%d)\n", GetLastError());
    return ;
    }
    }
    }
    return ;
    }

    邮槽通信客户端程序

    通过mailslot进程间通信-客户端
    通过mailslot进程间通信
    **************************************/
    /* 头文件 */
    #include
    <windows.h>
    #include
    <stdio.h>
    /* 全局变量 */
    HANDLE hSlot;
    LPTSTR lpszSlotName
    = TEXT("\\\\.\\mailslot\\sample_mailslot"); // mailslot名
    LPTSTR lpszMessage = TEXT("Test Message for mailslot "); // 通信的内容

    /* ************************************
    * void main()
    * 功能 进程间mailslot通信客户端
    *************************************
    */
    void main()
    {
    BOOL fResult;
    HANDLE hFile;
    DWORD cbWritten;

    DWORD cbMessage;
    // 打开mailslot
    hFile = CreateFile(lpszSlotName,
    GENERIC_WRITE,
    // 可写
    FILE_SHARE_READ,
    (LPSECURITY_ATTRIBUTES) NULL,
    OPEN_EXISTING,
    // 打开一个已经存在的mailslot,应该由服务端已经创建
    FILE_ATTRIBUTE_NORMAL,
    (HANDLE) NULL);

    if (hFile == INVALID_HANDLE_VALUE)
    {
    printf(
    "CreateFile failed with %d.\n", GetLastError());
    return ;
    }
    // 向mailslot写入
    fResult = WriteFile(hFile,
    lpszMessage,
    (DWORD) (lstrlen(lpszMessage)
    +1)*sizeof(TCHAR),
    &cbWritten,
    (LPOVERLAPPED) NULL);

    if (!fResult)
    {
    printf(
    "WriteFile failed with %d.\n", GetLastError());
    return ;
    }
    // 结束
    printf("Slot written to successfully.\n");
    CloseHandle(hFile);
    return ;
    }

    参考

    [1] 精通Windows API 函数、接口、编程实例

    [2] http://www.cnblogs.com/mydomain/archive/2011/01/07/1929874.html

    [3] http://msdn.microsoft.com/en-us/library/aa365130%28VS.85%29.aspx

    [4] http://www.cnblogs.com/mydomain/archive/2010/09/18/1830476.html?login=1

  • 相关阅读:
    C# 实现 Snowflake算法生成唯一性Id
    kafka可视化客户端工具(Kafka Tool)的基本使用(转)
    docker 安装kafka
    Model类代码生成器
    使用docker 部署rabbitmq 镜像
    Vue 增删改查 demo
    git 提交代码到库
    Android ble蓝牙问题
    mac 配置 ssh 到git (Could not resolve hostname github.com, Failed to connect to github.com port 443 Operation timed out)
    okhttp
  • 原文地址:https://www.cnblogs.com/mydomain/p/1931539.html
Copyright © 2020-2023  润新知