简介
有时候我们需要一个程序与另一个程序之间进行通信。你可能在多台机器上有多个服务器运行,而在一个中央位置对一个或多个服务器进行远程监控。Windows平台为我们提供了一系列通信方式,从Socket到命名管道,DDE,DCOM,邮槽等。本文中作者将探讨邮槽这一通信机制,假定读者熟悉CreateFile(),ReadFile(),WriteFile()等API函数,此外还假定读者熟悉重叠I/O的基础知识。
邮槽
实现一个“多写者/单读者”协议。一个进程通过指定一个名称创建一个邮槽,然后等待有消息写入到邮槽中。若其他进程知道邮槽的名称,则可以打开邮槽,往邮槽中写入消息。只能有一个邮槽读者,但可以有多个写者。微软使用服务器/客户来描述。服务器创建邮槽并从中读取消息。客户连接到一个已经存在的邮槽,并往里面写入消息。
邮槽有一个有趣而有用的属性。一个进程往邮槽中写入一个消息,读者就可以接收到消息。消息是一整块任意长度的数据,若写者写入60字节,读者读到60字节,不多不少。若写者写327字节,读者读到327字节。这是一个面向消息的协议,而不是面向字节的协议。这类似于命名管道上的消息模式。这并不是说你不能只读取消息的一部分,只不过使用邮槽的“自然”方式是面向消息的,这在对读者可用的API里反映出来。
邮槽可以跨网络使用。若在同一台机器上,则你可以给邮槽命名为""."mailslot"slotname。若跨网络使用,则你可以将”.”替换为创建邮槽的机器的名称。
创建邮槽
这通过CreateMailslot()函数完成,第一个参数指明了邮槽名称。其他参数依次是能写入邮槽中的消息的最大大小,邮槽读者等待消息的时间,一个指明句柄是否被子进程继承的安全描述符。
连接邮槽
你可以使用CreateFile()函数,在其中指定邮槽名称来实现。若你希望实现多写者/单读者模式,你必须在打开邮槽时小心共享模式。若邮槽写者打开邮槽时没有指定FILE_SHARE_WRITE为共享模式,那么它将阻止其他任何写者往邮槽里写入消息。
邮槽的句柄,何以处之?
若你通过CreateMailslot()函数创建邮槽,你可以使用ReadFile()从中读取消息。邮槽句柄在重叠I/O模式中创建,因此你可以在它上面使用重叠I/O,当然若合适的话,你也可以使用非重叠I/O模式。你可以调用GetMailslotInfo()函数来查询有等待被读取的消息的个数,下一个消息的长度,读取消息的超时时限。你可以调用SetMailslotInfo()函数来改变超时时限。注意你传递给这两个函数的句柄必须是通过CreateMailslot()创建的。
若你没有创建邮槽,然后你使用CreateFile()函数连接到邮槽上。这种情况下你可以使用WriteFile()函数往邮槽里写入消息。你能否使用重叠I/O模式取决于你如何调用CreateFile()函数的方式。它可以是同步的,也可以是异步的。你无法使用CreateFile()函数连接到一个邮槽上并且从邮槽上读取消息。
MSDN关于的邮槽的文档说只要邮槽上有任何一个打开句柄,邮槽就会存在。但作者说这不一定正确(在win xp sp2上)。你可以有任何数量的打开的邮槽写句柄,但只要读者句柄一关闭,邮槽就消失了(一旦读句柄关闭,往邮槽中写入消息就会失败)。这是有意义的。因为你只有一个读者,它一旦走了,那么任何写入的消息都只会被系统无意义地缓存。若没有读者了,那么缓存的消息就会永远悬停了(记住你无法使用CreateFile()来打开邮槽的读句柄)。
可以连接到特定域的特定名字的所有邮槽。这通过指定邮槽名称为“""domainname"mailslot"name“。也可以使用”*”作为首要域。这看起来不错,你可以在一个域内运行的多台机器上的任何数量的读者,并且指定域名同时往邮槽中写入消息。但有个问题,若你使用域名作为邮槽的写者,你没法写入大于424字节的消息。
BOOLMakeslot()
{//创建邮槽
CStringlpszSlotName=_T("////.//mailslot//sample_mailslot");
//Themailslothandle"hSlot1"isdeclaredglobally.
hSlot1=CreateMailslot(lpszSlotName.GetBuffer(10),
0,//nomaximummessagesize
MAILSLOT_WAIT_FOREVER,//notime-outforoperations
(LPSECURITY_ATTRIBUTES)NULL);//nosecurityattributes
if(hSlot1==INVALID_HANDLE_VALUE)
{
returnFALSE;
}
returnTRUE;
}
BOOLReadslot()
{//读邮槽
DWORDcbMessage,cMessage,cbRead;
BOOLfResult;
LPWSTRlpszBuffer;
TCHARachID[80];
DWORDcAllMessages;
HANDLEhEvent;
OVERLAPPEDov;
cbMessage=cMessage=cbRead=0;
hEvent=CreateEvent(NULL,FALSE,FALSE,_T("ExampleSlot"));
ov.Offset=0;
ov.OffsetHigh=0;
ov.hEvent=hEvent;
//Mailslothandle"hSlot1"isdeclaredglobally.
fResult=GetMailslotInfo(hSlot1,//mailslothandle
(LPDWORD)NULL,//nomaximummessagesize
&cbMessage,//sizeofnextmessage
&cMessage,//numberofmessages
(LPDWORD)NULL);//noreadtime-out
if(!fResult)
{
//ErrorHandler(hwnd,"GetMailslotInfo");
returnFALSE;
}
if(cbMessage==MAILSLOT_NO_MESSAGE)
{
//TextOut(hdc,10,10,"Nowaitingmessages.",20);
returnTRUE;
}
cAllMessages=cMessage;
while(cMessage!=0)//retrieveallmessages
{
//Createamessage-numberstring.
wsprintf((LPWSTR)achID,
_T("/nMessage#%dof%d/n"),cAllMessages-cMessage+1,
cAllMessages);
//Allocatememoryforthemessage.
lpszBuffer=(LPWSTR)GlobalAlloc(GPTR,
lstrlen((LPWSTR)achID)+cbMessage);
lpszBuffer[0]='/0';
fResult=ReadFile(hSlot1,
lpszBuffer,
cbMessage,
&cbRead,
&ov);
if(!fResult)
{
//ErrorHandler(hwnd,"ReadFile");
GlobalFree((HGLOBAL)lpszBuffer);
returnFALSE;
}
//Concatenatethemessageandthemessage-numberstring.
lstrcat(lpszBuffer,(LPWSTR)achID);
GlobalFree((HGLOBAL)lpszBuffer);
fResult=GetMailslotInfo(hSlot1,//mailslothandle
(LPDWORD)NULL,//nomaximummessagesize
&cbMessage,//sizeofnextmessage
&cMessage,//numberofmessages
(LPDWORD)NULL);//noreadtime-out
if(!fResult)
{
returnFALSE;
}
}
returnTRUE;
}
BOOLWriteslot()
{//写邮槽
CStringlpszMessage=_T("Messageforsample_mailslotinprimarydomain.");
BOOLfResult;
HANDLEhFile;
DWORDcbWritten;
hFile=CreateFile(_T("////.//mailslot//sample_mailslot"),
GENERIC_WRITE,
FILE_SHARE_READ,//requiredtowritetoamailslot
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE)NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
returnFALSE;
}
fResult=WriteFile(hFile,
lpszMessage.GetBuffer(10),
(DWORD)lstrlen(lpszMessage)+1,//includeterminatingnull
&cbWritten,
(LPOVERLAPPED)NULL);
if(!fResult)
{
returnFALSE;
}
fResult=CloseHandle(hFile);
if(!fResult)
{
returnFALSE;
}
returnTRUE;
}
分享到:
相关推荐
进程间通信,进程间通信,邮槽进程间通信,进程间通信,邮槽进程间通信,进程间通信,邮槽
本实例利用邮槽技术实现两个进程间的通信,包括发送数据和接收数据。
通过mailsolt来实现进程间通信,使用方法: 两个exe,一个服务端一个客户端,打开服务端创建邮槽 再打开客户端输入要发送的信息点击发送 回到服务端点击接受,注意每次发送信息前都需要创建邮槽。
用邮槽实现在windows下的进程间通信
进程间通信的VC++源码实例集,进程之间的通信以及实现方法实例,通过一些小程序来实现,这些小程序有剪贴板实例、邮槽、匿名管道等,希望对VC++基础用户有帮助。
运用邮槽进行进程间的通信,也是进程间通信的方法之一。
进程间通过邮槽通信实例,平台VS2010。这只是一个简单实例,供大家学习参考用。本人也只是菜鸟一个。
进程间通信的VC++源码实例集,邮槽、匿名管道等。
VC++ 四种进程间通信的完整实例,一般来说,进程通信采取四种形式:剪贴板、匿名管道、命名管道、邮槽。孙鑫将带你用实例来验证这四种方式的优略性,进而帮助VC编程者熟悉掌握进程间通信的方方面面,并附有孙鑫老师...
c++ 进程间通信 四种方式:剪贴板 匿名管道 命名管道 邮槽
Windows 的IPC(进程间通信)机制主要是异步管道和命名管道。(至于其他的IPC方式,例如内存映射、邮槽等这里就不介绍了) 管道(pipe)是用于进程间通信的共享内存区域。创建管道的进程称为管道服务器,而连接到这...
vc 实现了4种进程间的通信,包括剪贴板 命名管道 匿名管道 邮槽
作用:通过邮槽实现跨网络进程间的一对多的单向通讯
详细讲解进程间通讯的四种方式:剪贴板、匿名管道、命名管道和邮槽。并比较分析这几种进程间通信的优点和缺点。
自己编网络聊天程序,运用了Socket和进程通信,仅供参考 压缩包里包含了:源码+可执行程序。
进程间通讯(即:同机通讯)和数据交换有多种方式:消息、共享内存、匿名(命名)管道、邮槽、Windows套接字等多种技术。“共享内存”(shared memory)可以定义为对一个以上的进程是可见的内存或存在于多个进程的虚拟...
这是一个多进程通信的程序,有一个主进程和各种类型的子进程进行通信。
VC++ 进程间通信 包括:剪贴板、匿名管道、命名管道、邮槽、共享内存,很适合学习和借鉴