现在的位置: 首页 > 综合 > 正文

进程间通信之邮槽

2014年02月06日 ⁄ 综合 ⁄ 共 5217字 ⁄ 字号 评论关闭

简介

有时候我们需要一个程序与另一个程序之间进行通信。你可能在多台机器上有多个服务器运行,而在一个中央位置对一个或多个服务器进行远程监控。
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
字节的消息。

BOOL Makeslot() 



//
创建邮槽


    CString lpszSlotName 
=
 _T(
"
////.//mailslot//sample_mailslot
"
); 

    

//
 The mailslot handle "hSlot1" is declared globally. 


    hSlot1 
=
 CreateMailslot(lpszSlotName.GetBuffer(
10
), 

        

0
,                             
//
 no maximum message size 


        MAILSLOT_WAIT_FOREVER,         
//
 no time-out for operations 


        (LPSECURITY_ATTRIBUTES) NULL); 
//
 no security attributes 


    
if
 (hSlot1 
==
 INVALID_HANDLE_VALUE) 

    




        

return
 FALSE; 

    }


 

     

return
 TRUE; 

}


 

 

BOOL Readslot() 


{
//
读邮槽


    DWORD cbMessage, cMessage, cbRead; 

    BOOL fResult; 

    LPWSTR lpszBuffer; 

    TCHAR achID[

80
]; 

    DWORD cAllMessages; 

    HANDLE hEvent;

    OVERLAPPED ov;

    cbMessage 

=
 cMessage 
=
 cbRead 
=
 
0
;

    hEvent 

=
 CreateEvent(NULL, FALSE, FALSE, _T(
"
ExampleSlot
"
));

    ov.Offset 

=
 
0
;

    ov.OffsetHigh 

=
 
0
;

    ov.hEvent 

=
 hEvent;

    

//
 Mailslot handle "hSlot1" is declared globally. 


    fResult 
=
 GetMailslotInfo(hSlot1, 
//
 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) 

    




        

//
ErrorHandler(hwnd, "GetMailslotInfo"); 


        
return
 FALSE; 

    }


 

    

if
 (cbMessage 
==
 MAILSLOT_NO_MESSAGE) 

    




        

//
TextOut(hdc, 10, 10, "No waiting messages.", 20); 


        
return
 TRUE; 

    }


 

    cAllMessages 

=
 cMessage; 

    

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


    



        

//
 Create a message-number string. 


        wsprintf((LPWSTR) achID, 

            _T(

"
/nMessage #%d of %d/n
"
), cAllMessages 
-
 cMessage 
+
 
1


            cAllMessages); 

        

//
 Allocate memory for the message. 


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

            

return
 FALSE; 

        }


 

        

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


        lstrcat(lpszBuffer, (LPWSTR) achID); 

        GlobalFree((HGLOBAL) lpszBuffer); 

 

        fResult 

=
 GetMailslotInfo(hSlot1, 
//
 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) 

        




            

return
 FALSE; 

        }


 

    }


 

    

return
 TRUE; 

}


 

 

BOOL Writeslot()


{
//
写邮槽


    CString lpszMessage 
=
 _T(
"
Message for sample_mailslot in primary domain.
"
); 

    BOOL fResult; 

    HANDLE hFile; 

    DWORD cbWritten; 

     

    hFile 

=
 CreateFile(_T(
"
////.//mailslot//sample_mailslot
"
), 

        GENERIC_WRITE, 

        FILE_SHARE_READ,  

//
 required to write to a mailslot 


        (LPSECURITY_ATTRIBUTES) NULL, 

        OPEN_EXISTING, 

        FILE_ATTRIBUTE_NORMAL, 

        (HANDLE) NULL); 

     

    

if
 (hFile 
==
 INVALID_HANDLE_VALUE) 

    




        

return
 FALSE; 

    }


 

     

    fResult 

=
 WriteFile(hFile, 

        lpszMessage.GetBuffer(

10
), 

        (DWORD) lstrlen(lpszMessage) 

+
 
1
,  
//
 include terminating null 


        
&
cbWritten, 

        (LPOVERLAPPED) NULL); 

     

    

if
 (
!
fResult) 

    




        

return
 FALSE; 

    }


 

    fResult 

=
 CloseHandle(hFile); 

     

    

if
 (
!
fResult) 

    




        

return
 FALSE; 

    }


 

    

return
 TRUE; 


}



作者:洞庭散人

抱歉!评论已关闭.