《Windows核心编程》---邮槽通信

邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠UDP数据传输协议。使用邮槽通信的进程分为客户端和服务端,邮槽由服务端创建,创建后,客户端可以通过邮槽名打开邮槽,在获得邮槽句柄后可以向邮槽写入消息。邮槽通信是单向的,只有服务端能从邮槽中读取消息,而客户端只能写入消息。消息是先进先出的。

通过邮槽通信的数据可以是任意格式的,但为了保证邮槽在各种Windows平台下都能够正常工作,邮槽通信一条消息的长度不能大于424字节。邮槽除了在本机上进行进程间通信外,还可以在主机之间进行通信。

实际上一个邮槽是驻留在内存中的一个Windows临时虚拟文件,利用Windows标准文件函数可以对邮槽写入或读取消息,但它不同于磁盘文件的地方是:当邮槽句柄被关闭后,邮槽中的消息将被全部删除。

 

因此,邮槽工作方式有三大特定:1)单向通信;2)广播消息;3)数据报传输。

 

1)邮槽的命名:

本机上邮槽命名格式://./mailslot/[path/]name

例如://./mailslot/win/asce_comment;

不同主机间命名格式://DomainName/mailslot/[path/]name;

                            //ComputerName/mailslot/[path/]name;

也可以使用通配符,以进行广播://*/mailslot/[path/]name;

格式的说明:前两个反斜杠之后的字符表示服务器所在机器的名称,圆点表示是本地主机;“mailslot”是硬编码的,这几个字符不能改变,但大小写无所谓。“[path/]name”当然就是邮槽名字了。

2)关键的API

CreateMailslot,创建一个邮槽对象:

HANDLE WINAPI CreateMailslot(

  __in      LPCTSTR lpName, //邮槽名

  __in      DWORD nMaxMessageSize, //单一消息最大长度,为了可以发送任意大小的消息,

//一般将该参数设置为0

  __in      DWORD lReadTimeout, //读超时的时间:0(如果没有消息时立即返回);

//MAILSLOT_WAIT_FOREVER(直到读到消息才返回)

  __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes //安全属性

);

例子如下:

#include <windows.h>

#include <stdio.h>

 

HANDLE hSlot;

LPTSTR Slot = TEXT("////.//mailslot//sample_mailslot");

 

BOOL WINAPI MakeSlot(LPTSTR lpszSlotName)

{

    hSlot = CreateMailslot(lpszSlotName,

        0,                             // no maximum message size

        MAILSLOT_WAIT_FOREVER,         // no time-out for operations

        (LPSECURITY_ATTRIBUTES) NULL); // default security

 

    if (hSlot == INVALID_HANDLE_VALUE)

    {

        printf("CreateMailslot failed with %d/n", GetLastError());

        return FALSE;

    }

    else printf("Mailslot created successfully./n");

    return TRUE;

}

 

void main()

{

   MakeSlot(Slot);

}

 

 

GetMailslotInfo,获取指定邮槽的相关信息:

BOOL WINAPI GetMailslotInfo(

  __in       HANDLE hMailslot, //邮槽的句柄

  __out_opt  LPDWORD lpMaxMessageSize,         //返回消息的最大长度

  __out_opt  LPDWORD lpNextSize, //返回下一条消息的长度

  __out_opt  LPDWORD lpMessageCount, //返回消息的数量

  __out_opt  LPDWORD lpReadTimeout //返回读超时时间

);

例子如下:(这个例子同时是一个完整的邮槽服务端)

#include <windows.h>

#include <tchar.h>

#include <stdio.h>

#include <strsafe.h>

 

HANDLE hSlot;

LPTSTR SlotName = TEXT("////.//mailslot//sample_mailslot");

 

BOOL ReadSlot()

{

    DWORD cbMessage, cMessage, cbRead;

    BOOL fResult;

    LPTSTR lpszBuffer;

    TCHAR achID[80];

    DWORD cAllMessages;

    HANDLE hEvent;

    OVERLAPPED ov;

 

    cbMessage = cMessage = cbRead = 0;

 

    hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("ExampleSlot"));

    if( NULL == hEvent )

        return FALSE;

    ov.Offset = 0;

    ov.OffsetHigh = 0;

    ov.hEvent = hEvent;

 

    fResult = GetMailslotInfo( hSlot, // mailslot handle

        (LPDWORD) NULL,               // no maximum message size

        &cbMessage,                   // size of next message

        &cMessage,                    // number of messages

        (LPDWORD) NULL);              // no read time-out

 

    if (!fResult)

    {

        printf("GetMailslotInfo failed with %d./n", GetLastError());

        return FALSE;

    }

 

    if (cbMessage == MAILSLOT_NO_MESSAGE)

    {

        printf("Waiting for a message.../n");

        return TRUE;

    }

 

    cAllMessages = cMessage;

 

    while (cMessage != 0)  // retrieve all messages

    {

        // Create a message-number string.

 

        StringCchPrintf((LPTSTR) achID,

            80,

            TEXT("/nMessage #%d of %d/n"),

            cAllMessages - cMessage + 1,

            cAllMessages);

 

        // Allocate memory for the message.

 

        lpszBuffer = (LPTSTR) GlobalAlloc(GPTR,

            lstrlen((LPTSTR) achID)*sizeof(TCHAR) + cbMessage);

        if( NULL == lpszBuffer )

            return FALSE;

        lpszBuffer[0] = '/0';

 

        fResult = ReadFile(hSlot,

            lpszBuffer,

            cbMessage,

            &cbRead,

            &ov);

 

        if (!fResult)

        {

            printf("ReadFile failed with %d./n", GetLastError());

            GlobalFree((HGLOBAL) lpszBuffer);

            return FALSE;

        }

 

        // Concatenate the message and the message-number string.

 

        StringCbCat(lpszBuffer,

                    lstrlen((LPTSTR) achID)*sizeof(TCHAR)+cbMessage,

                    (LPTSTR) achID);

 

        // Display the message.

 

        _tprintf(TEXT("Contents of the mailslot: %s/n"), lpszBuffer);

 

        GlobalFree((HGLOBAL) lpszBuffer);

 

        fResult = GetMailslotInfo(hSlot,  // mailslot handle

            (LPDWORD) NULL,               // no maximum message size

            &cbMessage,                   // size of next message

            &cMessage,                    // number of messages

            (LPDWORD) NULL);              // no read time-out

 

        if (!fResult)

        {

            printf("GetMailslotInfo failed (%d)/n", GetLastError());

            return FALSE;

        }

    }

    CloseHandle(hEvent);

    return TRUE;

}

 

BOOL WINAPI MakeSlot(LPTSTR lpszSlotName)

{

    hSlot = CreateMailslot(lpszSlotName,

        0,                             // no maximum message size

        MAILSLOT_WAIT_FOREVER,         // no time-out for operations

        (LPSECURITY_ATTRIBUTES) NULL); // default security

 

    if (hSlot == INVALID_HANDLE_VALUE)

    {

        printf("CreateMailslot failed with %d/n", GetLastError());

        return FALSE;

    }

    return TRUE;

}

 

void main()

{

   MakeSlot(SlotName);

 

   while(TRUE)

   {

      ReadSlot();

      Sleep(3000);

   }

}

 

SetMailslotInfo,修改已创建邮槽读操作的超时时间:

BOOL WINAPI SetMailslotInfo(

  __in  HANDLE hMailslot, //邮槽句柄

  __in  DWORD lReadTimeout //新的读超时时间

);

 

邮槽的客户端代码如下:

#include <windows.h>

#include <stdio.h>

 

LPTSTR SlotName = TEXT("////.//mailslot//sample_mailslot");

 

BOOL WriteSlot(HANDLE hSlot, LPTSTR lpszMessage)

{

   BOOL fResult;

   DWORD cbWritten;

 

   fResult = WriteFile(hSlot,

     lpszMessage,

     (DWORD) (lstrlen(lpszMessage)+1)*sizeof(TCHAR), 

     &cbWritten,

     (LPOVERLAPPED) NULL);

 

   if (!fResult)

   {

      printf("WriteFile failed with %d./n", GetLastError());

      return FALSE;

   }

 

   printf("Slot written to successfully./n");

 

   return TRUE;

}

 

int main()

{

   HANDLE hFile;

 

   hFile = CreateFile(SlotName,

     GENERIC_WRITE,

     FILE_SHARE_READ,

     (LPSECURITY_ATTRIBUTES) NULL,

     OPEN_EXISTING,

     FILE_ATTRIBUTE_NORMAL,

     (HANDLE) NULL);

 

   if (hFile == INVALID_HANDLE_VALUE)

   {

      printf("CreateFile failed with %d./n", GetLastError());

      return FALSE;

   }

 

   WriteSlot(hFile, TEXT("Message one for mailslot."));

   WriteSlot(hFile, TEXT("Message two for mailslot."));

 

   Sleep(5000);

 

   WriteSlot(hFile, TEXT("Message three for mailslot."));

 

   CloseHandle(hFile);

 

   return TRUE;

}

 

由于邮槽是基于广播通信的,所以邮槽可以实现一对多的单向通信,例如,我们可以利用邮槽编写一个网络会议的通知系统。在每个被通知人电脑上安装服务端,通知人电脑上安装客户端即可。

posted on 2010-06-25 15:14  android开发实例  阅读(463)  评论(0编辑  收藏  举报

导航