摘 要: 本文论述了在Win9x,NT等Win32操作系统下,利用Delphi 封装MailSlots在局域网内实现实时通讯及网络数据广播。
关键词:Mailslots , Win32, 多线程。
Mailslots是Windows interprocess communications(IPC)的成员。Slot是通道的意思,顾名思义即Mailslots可在局域网上进行数据通讯。Mailslots的通讯是单方向的,但可很简便的实现网络数据广播。本文主要介绍用Mailslots进行通讯。
一、Maislots的函数
下面看mailslots 的函数
Mailslots Server的主要函数:
CreateMailslot
建立Server mailslot返回句柄
GetMailslotInfo 返回消息的数目、大小、等待时间等
ReadFile 从mailslot内取得消息
CloseHandle 关闭mailslot
Mailslots Client 的主要函数:
CreateFile 建立Client mailslot返回句柄
WriteFile 把数据写入mailslot
CloseHandle 关闭mailslot
读者也许会感到奇怪,怎么Mailslots和文件I/O函数一样的?mailsots其实是在内存里的临时的虚拟的文件,它和磁盘文件不同的是一旦关闭mailslots,所有在mailslots内的数据会删掉。
二、Mailslots Names
Mailslots Names 是很重要的,下面介绍它的格式:
CreateMailslot建立Server mailslot,mailslot Names必须如下的格式:
\\.\mailslot\[path]name
而CreateFile 建立Client mailslot , Mailslots Names有几种格式:
1 \\computername\mailslot\[path]name
消息写入指定的计算机的mailslot, 即消息只有指定的计算机有相同的Mailslot Name才可以接收。
2 \\domainname\mailslot\[path]name
domainname(工作组),工作组内有相同的Mailslot Name都可以接收消息
3 \\*\mailslot\[path]name
有相同的Mailslot Name(在系统主工作组内)都可以接收消息
如何实现网络广播了,局域网内“听众”建立相同的Mailslots Names,“电台”用2或3格式便可进行广播。
三、封装好的Tmailslot的源程序
Mailslot.pas 的内容:
//作者:江天送 Jun. 17th 2000
unit MailSlot; interface
uses
Windows, SysUtils, Classes;
type TOnReceiveData = procedure(Data: Pointer; Size: Cardinal) of object;
type
TMailSlotThread = class(TThread) //等待消息的线程
private
FHandle:THandle;
//Server Mailslot的句柄
cbMessage:Cardinal;
protected
procedure Execute; override;
Procedure ReceiveMessage;
public
Constructor Create(MSHandle:THandle);
end;
type
TMailSlot = class(TComponent)
private
msthread:TMailSlotThread;
FActive:Boolean;
FOnReceiveData:TOnReceiveData;
procedure SetActive(Value: Boolean);
protected
public
hMailSlot:THandle;
function WriteData(SlotName:pchar;Data:Pointer;
DataSize:Cardinal):Boolean;
function CreateSlot(SlotName:Pchar):Boolean;
function FreeSlot:Boolean;
published
property Active: Boolean read FActive write SetActive;
property OnReceiveData: TOnReceiveData
read FOnReceiveData write FOnReceiveData;
end;
var GOnReceiveData:TOnReceiveData;
procedure ReadMessage(FHandle:THandle;Size:Cardinal);
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Simple', [TMailSlot]);
end; //注册控件
function TMailSlot.CreateSlot(SlotName:Pchar):
Boolean;
begin //建立Server MailSlot
hMailSlot:=CreateMailslot(
SlotName, //MailSlot Name
0, // 没有最大消息长度的限制
MAILSLOT_WAIT_FOREVER, // 读取消息没有超时限制
nil);
if hMailSlot <> INVALID_HANDLE_VALUE then
begin //mailslot建立成功,启动线程
msthread:=TMailSlotThread.Create(hMailSlot);
GOnReceiveData:=FOnReceiveData;
Result:=TRUE;
end;
end;
function TMailSlot.FreeSlot:Boolean;
begin
if hMailSlot=0 then exit;
msthread.Terminate ;
CloseHandle(hMailSlot); //关闭Server MailSlot
end;
procedure TMailSlot.SetActive(Value:Boolean);
begin //设置线程的活动状态
FActive:=Value ;
if msthread=nil then exit;
if (Value) and (msthread.Suspended)
then msthread.Resume else msthread.Suspend;
end;
function TMailSlot.WriteData(SlotName:pchar;
Data:Pointer;DataSize:Cardinal):Boolean;
var
hFile:THANDLE ;
cbWritten:DWORD ;
begin //向MailSlot写数据
hFile := CreateFile(SlotName,GENERIC_WRITE,
FILE_SHARE_READ, //此处必须用FILE_SHARE_READ
nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
if hFile = INVALID_HANDLE_VALUE then
begin //CreateFile失败,返回FALSE
result:=FALSE;
exit;
end;
result:=WriteFile(hFile,data^,datasize,cbWritten,nil);
CloseHandle(hFile);
end;
Constructor TMailSlotThread.Create(MSHandle:THandle);
begin
Inherited Create(True);
FreeOnTerminate := True;
Priority := tpLowest;
//Priority设得太高会使GetMailSlotInfo出错
FHandle := MSHandle;
Resume;
end;
procedure TMailSlotThread.Execute;
var
Nmessage: cardinal;
begin
freeonterminate:=true;
repeat
cbMessage:=0;
Nmessage:=0;
GetMailslotInfo( FHandle, //MailSlot的句柄
nil, //没有最大消息长度的限制
cbMessage, //下个消息的长度
@Nmessage, //消息的个数
nil //读取消息没有超时限制
);
if NMessage>0 then
Synchronize(receiveMessage);
until terminated;
end;
procedure ReadMessage(FHandle:THandle;Size:Cardinal);
var cbread:Cardinal;
lpszBuffer:Pointer;
begin
getmem(lpszbuffer,Size);
ReadFile(FHandle,lpszBuffer^,
Size,cbRead, nil); //读取数据
if Assigned(GOnReceiveData)
then GOnReceiveData(lpszbuffer,cbRead);
freemem(lpszbuffer,Size);
end;
procedure TMailSlotThread.ReceiveMessage;
begin
ReadMessage(FHandle,cbMessage);
end;
end.
四、TMailSlot控件的使用
控件的使用很简单,Server方CreateSlot便可建立Server Mailslts,可用Active属性控制是否接收消息,用完别忘了FreeSlot关闭MailSlot。
Client方WriteData便可,用于网络广播每次写数据不可大于424字节。
|