织梦CMS - 轻松建站从此开始!

罗索

Win32 行程通讯的观念与技术

罗索客 发布于 2003-01-27 15:25 点击:次 
窗子提供的永远只是局部的风景。身为窗子的制造者以及使用者的我们不可能不明白这个道理;对於窗子的使用者日益挑剔的品味,窗子的制造者所能提供的不仅止於窗子的大小,往往是窗子的数量。的确,探出窗去看得将更多一些,外头天空地宽朗朗白日,别的窗子也许正有我们想
TAG:

窗子提供的永远只是局部的风景。身为窗子的制造者以及使用者的我们不可能不明白这个道理;对於窗子的使用者日益挑剔的品味,窗子的制造者所能提供的不仅止於窗子的大小,往往是窗子的数量。的确,探出窗去看得将更多一些,外头天空地宽朗朗白日,别的窗子也许正有我们想要的风景。

这篇文章谈的是 Interprocess Communication (IPC),我将与你分享跨行程通讯的各项技术与资料交换的方法。

为什麽需要 IPC?
为什麽需要 Inter-process Communication?

显而易见的,没有一个视窗应用程式可以包办全部的工作。为了避免资料重覆输入的时间浪费与人为错误,各应用程式间的资料会有互相交换的需求。首先的压力将来自於使用者,甚至於很可能是你自己。先不说别的,在写这篇文章时,我就曾剪贴原来以 Delphi 撰写的程式到文书编辑软体,同时,也利用抓图软体帮我拍下执行画面,最後,这些文章与范例程式得用压缩程式压起来,然後E-mail寄给杂志编辑。

使用 IPC 在某些情况下是不得不然的决定,有时候程式必须跨过机器边界让另一部机器内的程式明白该怎麽合作来共同完成工作,这同时也暗示我们可能面临不同的作业系统的问题。

此外,IPC有助於系统的安全与稳定。由於Win32各个行程彼此独立的特性,一个行程死掉了,其他的行程还可以继续跑下去,对於某些稳定性要求很高的系统而言

值得以额外的负担(Overhead)交换系统的强固性(robustness)。嗯! 我的意思是说,因为系统对稳定性的需求要求较高,值得拆开来做甚至额外的备援系统,既然工作拆成两个以上,此时必然需要IPC。

关於IPC,一般人可能会对其有「执行效率缓慢」的印象,这当然不能说是错误的,但绝不是公平的评语。这麽说吧:一个主管亲自去做一件事,往往会比先说明再授权下属去做来得快,这是单一工作时的情况;然而如果管理者同时有好几件事在手上,托付别人去做才能使得整个公司的效能提高。换句话说,如果能善用 IPC,整体的系统效能不仅不会下降,反而可能因为充分利用整个运算群的能力而有提升。


我们的第一个 IPC 例子

每个图形介面的视窗应用程式都接受并处理讯息(Message),因此,使用讯息伫列通知其他的行程是脑中很自然会浮现的第一个想法;换句话说,两行程间彼此互相以 SendMessage() 或 PostMessage() 传送讯息通知对方。

即然要互送讯息,就需要一个彼此都认得的讯息编号。於是,除了 Windows 标准的讯息编号之外,我们还需要额外定义一个(一些)讯息。

行程通讯间用来约定讯息编号常用的方法是呼叫RegisterWindowMessage() API函数。这个函数只有一个字串型别的引数,Windows系统会检查我们传入的讯息名称并传回一个安全不重覆的讯息编号,假如传入的讯息名称早已经登记有案,则系统传回的是稍早传给那个行程的相同编号。

换句话说,两支程式只要彼此都用相同的讯息名称呼叫RegisterWindowMessage() 注册讯息,系统便会都给两者一个相同的自订讯息编号。

接下来要送出讯息了,可是,要送给谁呢?嗯,我在这 使用的方法是:第一次先用广播的,每一个视窗程式都会收到通知,讯息的短叁数(wParam)中写明发讯视窗的 Handle 值,如果是同志,它自然明白这个讯息代表了什麽,并且也使用SendMessage() 回送约定的讯息表示收到。同样的,讯息的短叁数注明自己的Handle。於是,茫茫人海的小俩口终於得知对方的下落,以後就不再需要公开寻人可以透过Handle值直接与对方联络了。

除了讯息编号,讯息的wParam,lParam长短叁数也可以用来进一步约定通讯的细节。事情进展得似乎十分顺利,现在我们知道合作对象,也确信它明白我们的讯息代表什麽。虽然简单,但是这种暗通款曲的方式是系统默许的。不过,我们还需要再多解决一个问题。

由於SendMessage 只有 wParam,lParam 两个 DWORD 型别的长短叁数,携带的资料量十分有限。很显然的,我们需要能够一次传送更多资料的方法。Windows 也的确提供了许多交换资料的机制,我在这篇文章中将会一一说明,其中最简便的方法是使用 WM_COPYDATA 讯息,作法如下


将资料内容指定到COPYDATASTRUCT这个资料结构中。

必须使用SendMessage()送出 WM_COPYDATA讯息,讯息的短叁数是发讯端视窗的Handle值,长叁数的内容则是指向COPYDATASTRUCT的指标。

受讯端行程收到讯息时,以长叁数提供的线索依址取回资料。

小俩口书信往返时系统是居中牵线的红娘。就在发讯视窗送出WM_COPYDATA讯息

受讯视窗取得内容之间,系统在背後默默接管记忆体管理的琐事。有关WM_COPYDATA的使用有一点需要提醒读者的,收讯端应该视这块记忆体是唯读的,如果後来程式处理需要这些资料,应该要先将之拷贝出来。

多亏有了这项特殊的性质,使得WM_COPYDATA与讯息沟通模型成为 Win32 平台上少数同时支援 16-bit与32-bit应用程式的IPC机制。你可以在WM_COPYDATA目录找到范例程式TwinApp的完整原始程式。


IPC基本概念的讨论

总结来说,上述的例子是两个行程彼此利用RegisterWindowMessage()注册所得的编号对送讯息,并且利用讯息的长短叁数进一步协定通讯的内容与细节,对於资料量比较大的资料则使用WM_COPYDATA。

眼尖的读者在检视TwinApp时也许会察觉到一些DDE的影子。当然,比起DDE来说,TwinApp范例程式的讯息沟通模型实在阳春,缺点也不少。不过我的用意本来就不在於一开始就写一个大型程式出来吓唬人;相反的,我打算提供一个简单的例子,并且从这个例子支解出有关行程通讯的几个重要的观念与特性,这些特性并不是TwinApp所独有的,对於其他IPC机制的讨论也有相同的价值,等我们扣紧了对IPC的感觉,再陆续讨论其他 Win32 平台所支援的IPC机制。

话说内行的看门道,外行的看热闹。或许我算不得顶尖高手,但至少应该比看热闹的多看出一些东西来吧! :p 观察TwinApp这个例子 --

行程之间彼此有共同的通讯协定

通讯的仅限於单机,稍候讨论的IPC有些则是可以跨过机器边界甚至网域.

Process在行程通讯中的角色扮演

一般来说,叁与IPC的行程可以归类成Client与Server两类,所谓的Server指的是提供服务的行程;Client指的是使用或向Server要求服务的行程。

真实的世界中,人的角色扮演是随情境而变的。我们会是别人的子女,但也同时是别人的爸妈; 即使同样是夫妻,居家生活与外出场合的行为表现也有差异。界定某一程式是Client与Server的角色端视当时的情况而定并非绝对的。举例来说,文书处理软体可能向试算表要求库存统计资料,此时试算表扮演的是Server的角色,但在试算表向库存管理系统索取统计资料的场合,试算表则是Client。

以我们的第一个例子TwinApp来说,彼此既接收讯息,同时也主动发出讯息。既可以是Client也可以是Server,没有明显的主从之别,对於这样的情况,有一个专有名词叫「对等模式」(Peer-to-peer model) 。

同步与非同步的讨论

TwinApp使用SendMessage()送出讯息,程式会暂停在SendMessage()那行等待讯息处理结束返回後再继续下一列程式,这样的情况属於同步处理。同步(Synchronous)与非同步(Asynchronous)在IPC中是一个非常重要的论题,有必要先对这两个名词先做说明:

假设程序A呼叫程序B时,若是A先暂停一直等到程序B结束返回後再继续程序A的下一动作,我们称其为同步(Synchronous);另一种情况是 -- 如果A呼叫B之後,不等B执行完,就直接进行A的下一动作,则是所谓的不同步。

以提款机为例,我们会先插入卡片,输入密码,键入金额,然後是内部安全与帐务查核,最後收回卡片及金额,列印交易明细,一动接一动按步就班;同样是提款这件事,某位老板可以交待会计小姐去提款,交待完之後他就迳自去忙别的事,等到会计小姐提[FS:PAGE]款回来,再向老板回报,这样的程序是所谓的非同步。

如果进一步观察提款这个例子:会计小姐什麽时候出门什麽时候回来是算不得准的,假定这位老板除了会计小姐之外,另外还交办旁人其他工作,可以预见的,不一定那一件工作会先做完。由於执行的次序无法预估,采用非同步方式设计的行程通讯将会多出许多协调与事件处理的工作,使得彼此之间总互相期待点什麽。

叁与通讯的行程个数,讯息资料的流向

在TwinApp中,简单的只有两个端点。但在实际应用的场合,Server通常得同时应付好几个Client的要求,如何妥善照顾到每一个Client同时要兼顾系统执行的效能,是门很大的学问。

当行程对行程搭起通讯的鹊挢时,这座挢是单行道或者是双向通行,同样也值得列入评估要素。不过有一点需要注意的: 不论选择单工或双工的IPC机制,并不构成我们建立双向沟通无可跨越的天堑,话说山不转路转,盖两座单向的挢一样可以有双向通行的效果,不过就先天本质的特性来说,某些IPC机制确实比较容易作出双工的效果,当然也有天生大嘴巴适合用来广播的,例如本文稍後叙述的MailSlot。

资料的可视性与安全性

交换的资料在行程之间当然必须是可见的,TwinApp是用WM_COPYDATA交出资料。IPC有些技术是可以让行程共同存取资料的,稍候我们在 Shared memory 时将有讨论.

是否需要有视窗或者纯Console Application也能应用.

TwinAPP是以SendMesasage()送出讯息,这表示需要有视窗才行得通。如果你设计的是纯Console Mode 的应用程式,那麽,选用不需要视窗Handle也行得通的IPC机制(例如pipe)会比较适合。

关於执行效能的讨论

许多人耽心IPC的执行效能,的确,先不说别的,光是启动另一个Process本身就比启动一个Thread 的Overhead要高上很多。如果涉及协调的问题,建立一个Mutex的时间也比Critical section慢上不知多少倍。遗憾的是我们却也别无选择,因为Critical section在Multi-Thread中固然简单好用,但是不能用在跨越行程边界的场合。

但是要说 IPC 一定使得系统效能降低,未免也太过悲观了;平视与俯看的视野是不同的。这年头大家都将Client/Server挂在嘴边,充分运用合理分配整个公司的运算资源才能提高整体的效能,我想 IPC 在这 自有其应用的价值与效益。

另外一个导致IPC执行效率不彰的元凶来自不良的设计,着名的例子是所谓的Busy-loop 一个什麽也不做只有一行程式不断地期待的回圈。以稍早的老板与会计小姐为例,如果老板交办事情之後却将全部的事都停下来,来回踱步只为专心等着会计小姐回来,时间没有花在刀口上的结果当然效率不彰。找出效率的瓶颈设法调校是件长期奋战的工作,如同管理是持续不断的合理化。

此处还有一个迷思也有待澄清,同步与非同步对於执行效能的影响是视情况而定的,并不能说非同步一定会比同步快,抽样样本很小或资料量偏小时,同步往往比非同步快。比较公允的说法应该是:同时有好几件工作要处理时,整体来说「非同步」往往快一些。以刚才的提款的事情为例,老板亲自去提款未必比小姐慢,但是如果老板同时有好几件工作要处理时,非同步的好处就很明显了。


Win32支援的IPC相关技术

上述的讨论与其说是针对TwinApp的观察,不如说是针对IPC的综合讨论。观念的说明之後是技术层次的讨论。接下来陆续介绍的是Win32 API支援的各项IPC机制 --

Clipboard
COM
Dynamic Data Exchange (DDE)
File Mapping
Mailslots
Pipes
RPC
Windows Sockets
WM_COPYDATA

剪贴簿(Clipboard)

人,其实是最佳的 IPC 机制,十分的聪明也十分的有弹性。

剪贴簿几乎是专为人类而设的标准资料交换中心。它最大的特色除了使用者导向之外,任何应用程式都允许改写其内容,同时它是可以跨越机器边界,交换的范围不仅限於单机内的各个行程。


由於它是纯使用者导向,使用剪贴簿的程式有一项传统是值得遵守的:如果不是基於使用者的操作,程式不应该主动去异动剪贴簿的内容;同样的道理,我们也不应该假设剪贴簿中有我们程式想要的资料,哪怕是不久前才刚放进去的,因为,使用者可能已经清除或改变其内容了。

剪贴簿几乎可以容纳任何的资料,除了标准支援的CF_TEXT、CF_BITMAP...等资料格式,我们可以自行注册登记其他格式的资料。但由於它的使用者导向,也由於任何程式都可以改写其内容,除非使用者愿意,不然坦白来说不太适合行程间的资料交换。这也使得应用设计IPC时,剪贴簿成为每支应用程式都标准支援但却也都适可而止的IPC机制。我们应该再多看看其他的资料交换方法。


File Mapping

在早期MS-DOS时代还没有现在这麽多 IPC机制可供利用时,使用磁碟档案来交换资料可说是一般应用程式的唯一选择。时至今日,档案不仅没有从IPC领域中消失,反而是更加发扬光大了,然而观念上早已不纯粹界定在档案系统的实体档案。的确,资料位於何处的份际如今是越来越模糊了,虚拟的记忆体实际上是档案,虚拟的档案结果是记忆体。

Win32 API 中有一个好玩的东西叫做File-mapping;基本的观念是开启一个档案并将之对映到某一块记忆体,有趣的是,虽然程式是针对这块记忆体操作,实际上改变的却是档案。

更好玩的是你不必真的在硬碟 开一个实体档案,而是使用分页置换档(paging file)的一块空间权充当作档案。这个虚拟的档案空间(或者你要说是记忆体)可以为行程间共享,通常我们管它一个特别的名字叫 Share-memory,共享记忆体。

由於它的确不是真正的档案,行程间不仅省去特定磁碟目录档案等约定,也毋须在意谁是最後走的要负责删除档案,当然啦,即使当机不会留下一些垃圾档案。彼此分享的是正好是同一块记忆体,资料一旦写入,这项改变也立即反应到别的行程。 (佚名)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/200301/2435.html]
本文出处:网络博客 作者:佚名
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容