`
helpbs
  • 浏览: 1163792 次
文章分类
社区版块
存档分类
最新评论

《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(

__inLPCTSTR lpName,//邮槽名

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

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

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

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

__in_optLPSECURITY_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());

returnFALSE;

}

elseprintf("Mailslot created successfully./n");

returnTRUE;

}

voidmain()

{

MakeSlot(Slot);

}

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

BOOL WINAPI GetMailslotInfo(

__inHANDLE hMailslot,//邮槽的句柄

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

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

__out_optLPDWORD lpMessageCount,//返回消息的数量

__out_optLPDWORD 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 )

returnFALSE;

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());

returnFALSE;

}

if(cbMessage == MAILSLOT_NO_MESSAGE)

{

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

returnTRUE;

}

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 )

returnFALSE;

lpszBuffer[0] ='/0';

fResult = ReadFile(hSlot,

lpszBuffer,

cbMessage,

&cbRead,

&ov);

if(!fResult)

{

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

GlobalFree((HGLOBAL) lpszBuffer);

returnFALSE;

}

// 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());

returnFALSE;

}

}

CloseHandle(hEvent);

returnTRUE;

}

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());

returnFALSE;

}

returnTRUE;

}

voidmain()

{

MakeSlot(SlotName);

while(TRUE)

{

ReadSlot();

Sleep(3000);

}

}

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

BOOL WINAPI SetMailslotInfo(

__inHANDLE hMailslot,//邮槽句柄

__inDWORD 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());

returnFALSE;

}

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

returnTRUE;

}

intmain()

{

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());

returnFALSE;

}

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);

returnTRUE;

}

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics