• 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

  • 相关阅读:
    再谈Dilworth定理
    区间动态规划
    单调队列优化动态规划
    暑假集训考试R2 konomi 慕
    NOIP 2000 计算器的改良
    2007 Simulation message
    COCI 2003 LIFTOVI 电梯 SPFA
    NOIP 2003 数字游戏
    USACO 2014 DEC Guard Mark 状态压缩
    使用HttpClient发送GET请求
  • 原文地址:https://www.cnblogs.com/mydomain/p/1931539.html
Copyright © 2020-2023  润新知