⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 008.htm

📁 Delphi书籍--Delphi网上教程
💻 HTM
📖 第 1 页 / 共 3 页
字号:
var<br> 
&nbsp;&nbsp;&nbsp; NextSize: DWORD;<br> 
&nbsp;&nbsp;&nbsp; MessageCount: DWORD;<br> 
&nbsp;&nbsp;&nbsp; Result: BOOL;<br> 
&nbsp;&nbsp;&nbsp; Buffer: pchar;<br> 
begin<br> 
&nbsp;&nbsp;&nbsp; if FHandle = INVALID_HANDLE_VALUE then Exit;<br> 
&nbsp;&nbsp;&nbsp; // 侦测 MailSlot 中是否有资料<br> 
&nbsp;&nbsp;&nbsp; Result := GetMailslotInfo(Fhandle, nil, <br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NextSize, @MessageCount, nil);<br> 
&nbsp;&nbsp;&nbsp; if not Result or (NextSize = MAILSLOT_NO_MESSAGE) then<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exit;<br> 
&nbsp;&nbsp;&nbsp; // 如果还有资料 (MessageCount &lt;&gt; 0),逐一读出资料<br> 
&nbsp;&nbsp;&nbsp; while Result and (MessageCount &lt;&gt; 0) do<br> 
&nbsp;&nbsp;&nbsp; begin<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 资料的长度<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Buffer := AllocMem(NextSize + 1);<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 读出资料<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileRead(Fhandle, 
Buffer^, NextSize);<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if 
Assigned(FOnDataAvailable) then<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FOnDataAvailable(Self, 
StrPas(Buffer));<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeMem(Buffer, 
NextSize + 1);<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 继续看看 MailSlot 中还有没有资料<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Result := GetMailslotInfo(Fhandle, nil,<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NextSize, @MessageCount, nil);<br> 
&nbsp;&nbsp;&nbsp; end;<br> 
end;<br> 
<br> 
至於MailSlot的Client程式则没有什麽好说的,就当是档案迳行开启与写入即可:<br> 
<br> 
procedure TMailSlotClient.Open;<br> 
var<br> 
&nbsp;&nbsp;&nbsp; ASlotName: string;<br> 
begin<br> 
&nbsp;&nbsp;&nbsp; if FActive then Exit;<br> 
&nbsp;&nbsp;&nbsp; // MailSlot 的识别名称<br> 
&nbsp;&nbsp;&nbsp; ASlotName := '\\' + FServerName + '\mailslot\' + FSlotName;<br> 
&nbsp;&nbsp;&nbsp; // 开启 MailSlot(档案)<br> 
&nbsp;&nbsp;&nbsp; FHandle := CreateFile(pchar(ASlotName), <br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GENERIC_WRITE, // Client 端对於 MailSlot 
只能写入<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILE_SHARE_READ, // 设定为可供分享读取<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);<br> 
&nbsp;&nbsp;&nbsp; FActive := FHandle &lt;&gt; INVALID_HANDLE_VALUE;<br> 
end; <br> 
<br> 
function TMailSlotClient.WriteIntoMailSlot(<br> 
&nbsp;&nbsp;&nbsp; const Data: string): integer;<br> 
begin<br> 
&nbsp;&nbsp;&nbsp; Result := 0;<br> 
&nbsp;&nbsp;&nbsp; if FHandle = INVALID_HANDLE_VALUE then Exit;<br> 
&nbsp;&nbsp;&nbsp; Result := FileWrite(Fhandle, Data[1], Length(Data));<br> 
end;<br> 
<br> 
&nbsp;&nbsp;&nbsp; 稍早提到MailSlot适合於跨越机器边界的网路广播, 
可是我也说明了只有MailSlot Server才可以读取资料,那要怎麽广播啊?答案在於MailSlot的名称。别的机器如果也用相同的名称建立MailSlot 
Server,一旦任一个Client对某一个MailSlot(也是经由名称来叁考)送出讯息,这份讯息会游向网路节点上各个指定同名的MailSlot,这样子就达成广播的效果。至於讯息是怎麽流来流去的,就留给系统与网路底层去伤脑筋了,程式只管以档案写入资料的方式送出资料即可。<br> 
&nbsp;&nbsp;&nbsp; 使用MailSlot时很可能你会遇到讯息重覆的问题;也就是说,虽然MailSlot 
Client端只写了一个讯息,但相同的讯息MailSlot Server却可能收到两份。原因是这样的:由於Win32多重通讯协定的缘故,MailSlot在广播时,并不知道到底该采用哪一条路径,於是便各种可能的通路都传了一份。情况有点像在发布台风警报,我们在电视,广播与网路都同时会晓得有台风要来的消息。解决的方法是在资料开头处加上一些控制用的编号代码,Server据以判断是否是相同的资料。<br> 
&nbsp;&nbsp;&nbsp; 像MailSlot这样的通讯机制可以应用在哪些场合呢? 
着名的例子是WinPopup,刚才我也写了一支阳春的, 次图是MyWinpop.exe 
执行的情况。由於MailSlot广播的特性,十分适合网管时用来知会使用者重要的讯息,此外,MIS系统也可以用它适时的报告异常状况,各使用者如果在「开始┃启动」中都放置这支小程式,彼此便可以之交换讯息,当讯号进来时,也会立即显示讯息的内容。<br> 
<br> 
<br> 
图: MyWinPop.exe执行情形<br> 
<br> 
&nbsp;&nbsp;&nbsp; 
当然,你还可以想得到其他的应用。像我就觉得它很适合用来作为程式除错工具,不仅可以将程式执行的过程与情况记录下来,而且程式在网路上各节点的执行状况也将源源而来,这是一般的测试方法所不容易达成的效果。<br> 
<br> 
<strong>Pipe</strong></span></p> 
<p><span class="p2">&nbsp;&nbsp;&nbsp; 看过广播式的 MailSlot後,Pipe则是点对点的通讯机制,资料允许单向或双向於管子连接的两端移动。pipe可分为Anonymous 
pipe与Named pipe 两种,Anonymous pipe的资料只能单向流动,而且仅限於单机内使用,但却是行程重导其标准输出(Standard 
Output)成为另一行程之标准输入的方法;Named pipe 
就如同先前讨论的各项IPC机制,由於有一个识别名称,其他的行程很容易可以依照名称找过来,通讯范围不限於单机,同时,资料允许双向流通。<br> 
<br> 
<strong>DDE</strong><br> 
<br> 
<strong>&nbsp;&nbsp;&nbsp; </strong>如同本文第一个TwinApp这个例子,DDE也是建立在讯息通讯这个基础上的,不过它的协定内容显然严谨很多。<br> 
&nbsp;&nbsp;&nbsp; DDE是由Client端以WM_DDE_INITIATE广播讯息起拉开通话的序幕,Server端受理後以WM_DDE_ACK回应,连通後则是一连串Server与Client间彼此互送WM_DDE_DATA、WM_DDE_REQUEST、WM_DDE_ACK等讯息。实际的资料并不是真的经由讯息传递,而是提供线索彼此利用Atoms(由Windows系统提供的字串对照表)寻求Application(应用程式), 
Topic(主题)与Data(资料)等三个项目。最後,以WM_DDE_TERMINATE讯息结束对话。<br> 
&nbsp;&nbsp;&nbsp; 行程间建立DDE连接时,当Server端的资料改变时,依资料交换的频繁与Client的主动程度,其通道的形态可分为:<br> 
&nbsp;&nbsp;&nbsp; Cold Link:来要才有;Client端得主动要求传送资料,如果没有来要,即使Server的资料已经改变很多了,Server对Client也置之不理。<br> 
&nbsp;&nbsp;&nbsp; Hot Link:有变就给;当资料改变时,Server端将主动通知Client改变的内容。 
</span><ul> 
<li><span class="p2">Warm Link:更新通知;当资料改变时,Server端只对Client端告知资料改变的消息,真正的资料要等Client提出要求才会送出。</span></li> 
</ul> 
<p><span class="p2">&nbsp;&nbsp;&nbsp; 由於DDE讯息通讯牵涉的实作细节颇多,为了使用方便起见,微软也提供DDE管理函式库(The 
DDE Management Library, 简称 DDEML), 使用上的最大差别在於使用DDEML的程式是用Callback函数处理DDE交易(Transaction) 
。另外,三大项目的Application改口叫做(Service name)服务。<br> 
&nbsp;&nbsp;&nbsp; 时至今日,讨论DDE的文献已不在少数,的确,DDE的使用应该是容易许多了,几乎没有一个Windows程式开发工具不提供一些元件或类别让程式员更方便制作DDE 
Server或Client程式。当然,如果你的需求只是在行程间通知某些消息,自行设计一套讯息通讯协定倒也简单得以完成任务,我想本文的第一个例子TwinApp是一个不错的提示。<br> 
<strong><br> 
其他的IPC技术<br> 
&nbsp;&nbsp;&nbsp; </strong>EXE通常呼叫DLL的输出函数(exports function),某些情况下DLL也会使用EXE 
事先预备的回呼(Callback)函数。函数呼叫这个观念与想法如果移植到行程通讯中会发生什麽事呢? 
我的意思是说,让一个行程呼叫另一个行程的函数。Ya! 
这就是所谓的 RPC,行程之间属於函数呼叫层级的合作。可以想见的,由於行程各有其定址空间,如同OLE,要达到 
RPC确实需要额外标准的介面加以定义。<br> 
&nbsp;&nbsp;&nbsp; 有关IPC的技术与观念我们已经介绍得不少了,不论是讯息交换,剪贴簿,Shared 
memory,DDE,MailSlot,Pipe等等,几乎都是资料的交换或者Client与Server「要求-回应」,叁与通讯的行讯必须对於交换的资料有一定程度的了解与处理能力。换句话说,在我们以DDE向试算表软体要求传回资料後,这份资料到底代表什麽得自己解释;同样的,如果要传入资料到试算表软体,即使透过现成元件的帮忙,仍然必须对试算表软体有基本的认识。<br> 
&nbsp;&nbsp;&nbsp; 
话说回来了,只有试算表自己最清楚资料代表什麽,不是吗?那麽,由它来处理资料应该才是适当的人选,强以外部程式去操作总有外行人指导内行人的遗憾。利用OLE技术将应用程式整合在一起工作确实是比较合理的作法,如果COM物件可以像电子IC一样安插进我们的程式与我们的程式一同工作,那这种我们称之为OLE 
Control(ActiveX),距离拉大到网路上,DCOM这个名词你一定听说过.<br> 
&nbsp;&nbsp;&nbsp; 
想想看,终於我们可以用甲公司的统计图表元件,然後用乙公司的元件将图表传真出去,这样窗景真是美好。窗子确实只提供局部的风景,但是加装了望远镜的窗子可是一个天文台,加了风铃的窗子所提供的就不只是风景了,还有悦耳的声音。<br> 
&nbsp;&nbsp;&nbsp; 不论是RPC或OLE,我想这都是属於本文应该讨论但肯定是来不及讨论的,这两个主题甚至以单篇文章来谈都不怎麽够用。事实上,有些地方(例如DDE这一节)我也没有提到技术方面的实作细节,碍於篇辐(这篇文章已经太长了) 
日後我们会在本专栏继续以专文介绍RPC等主题。关於以Winsock作为IPC通讯机制这部分,本专栏的前一篇文章「走! 
让我们上BBS聊天去」才刚说明过,在此就不再重覆了。<br> 
<br> 
<strong>应用IPC到你的程式中</strong><br> 
<strong>&nbsp;&nbsp;&nbsp; </strong>各项IPC的技术往往以各种方式组合在一起。例如本文提供的DemoSMem范例程式就同时用了ShareMem交换资料,同步机制则采用Mutex与Event。情况并不如想像中的复杂:既是行程通讯,那必然是两个以上行程之间的事,既是分开的,中间一定有介面存在,定义这个介面的具体内容就是所谓的协定,留意资料交换的位置与方式,需要协调避让的采用合适的同步控制加以处理。这些重点把握住了,应该心 
就已经有数了。<br> 
&nbsp;&nbsp;&nbsp; 面对各式各样的技术时,如果你正考虑应用IPC到你的程式中,首先得正视自己的需求,不妨提出类似以下的问题问问自己,最好将之写下来 
</span><ul> 
<li><span class="p2">是否真的需要跨行程处理,成效何在?</span></li> 
<li><span class="p2">技术实作的难易程度与所需付出的成本</span></li> 
<li><span class="p2">资料的流向是单向或双向,需不需反馈(feedback)的控制查核</span></li> 
<li><span class="p2">这些工作只在单机完成,或者需要连上网路,范围只在公司内部区域网路或者是广域网路</span></li> 
<li><span class="p2">叁与通讯的行程最多与平均的数量是多少?</span></li> 
<li><span class="p2">只在一种作业环境,或者可能同时要满足不同的作业平台</span></li> 
<li><span class="p2">执行效能( performance)是不是关键需求.</span></li> 
<li><span class="p2">应用程式使用 GUI 介面或者 console mode</span></li> 
</ul> 
<p><span class="p2">&nbsp;&nbsp; 接下来开始比较各项IPC的特性,哪些是与你列出的需求相符合的,有没有哪些限制是你必须要排除而避免使用的,各项IPC经过与先前写下的需求交叉评比的结果,积分高的自然是脱颖而出。最後,事情如果能简单解决是最好,开发时程缩短成本自然降低,而且日後维护容易。<br> 
<br> 
<strong>结语</strong><br> 
<strong>&nbsp;&nbsp;&nbsp;&nbsp; </strong>技术是不断推陈出新的,当各式各样的IPC机制提出时,回顾行程之所以开始通讯合作的初衷是有必要的,唯有回到最初原始的简单需求,才能看出技术演进过程的缘由与其修正的价值,不断的变易之中我们可以粹化出一些不变的原则与观念,而这些原则应该是与最初的需求互相吻合的</span></p> 
<hr color="#EE9B73" size="1" width="94%"> 
 
</TD> 
 
</TR> 
</table> 
</BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -