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

📄 ipc.htm

📁 对于学习很有帮助
💻 HTM
📖 第 1 页 / 共 3 页
字号:
  &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;</p>
  <p>至於MailSlot的Client程式则没有什麽好说的,就当是档案迳行开启与写入即可:</p>
  <p>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; </p>
  <p>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;</p>
  <p>稍早提到MailSlot适合於跨越机器边界的网路广播, 
  可是我也说明了只有MailSlot Server才可以读取资料,那要怎麽广播啊?答案在於MailSlot的名称。别的机器如果也用相同的名称建立MailSlot 
  Server,一旦任一个Client对某一个MailSlot(也是经由名称来叁考)送出讯息,这份讯息会游向网路节点上各个指定同名的MailSlot,这样子就达成广播的效果。至於讯息是怎麽流来流去的,就留给系统与网路底层去伤脑筋了,程式只管以档案写入资料的方式送出资料即可。</p>
  <p>使用MailSlot时很可能你会遇到讯息重覆的问题;也就是说,虽然MailSlot 
  Client端只写了一个讯息,但相同的讯息MailSlot Server却可能收到两份。原因是这样的:由於Win32多重通讯协定的缘故,MailSlot在广播时,并不知道到底该采用哪一条路径,於是便各种可能的通路都传了一份。情况有点像在发布台风警报,我们在电视,广播与网路都同时会晓得有台风要来的消息。解决的方法是在资料开头处加上一些控制用的编号代码,Server据以判断是否是相同的资料。</p>
  <p>像MailSlot这样的通讯机制可以应用在哪些场合呢? 着名的例子是WinPopup,刚才我也写了一支阳春的, 
  次图是MyWinpop.exe 执行的情况。由於MailSlot广播的特性,十分适合网管时用来知会使用者重要的讯息,此外,MIS系统也可以用它适时的报告异常状况,各使用者如果在「开始┃启动」中都放置这支小程式,彼此便可以之交换讯息,当讯号进来时,也会立即显示讯息的内容。</p>
  <p><br>
  图: MyWinPop.exe执行情形</p>
  <p>当然,你还可以想得到其他的应用。像我就觉得它很适合用来作为程式除错工具,不仅可以将程式执行的过程与情况记录下来,而且程式在网路上各节点的执行状况也将源源而来,这是一般的测试方法所不容易达成的效果。</p>
</blockquote>

<h3>Pipe</h3>

<blockquote>
  <p>看过广播式的 MailSlot後,Pipe则是点对点的通讯机制,资料允许单向或双向於管子连接的两端移动。pipe可分为Anonymous 
  pipe与Named pipe 两种,Anonymous pipe的资料只能单向流动,而且仅限於单机内使用,但却是行程重导其标准输出(Standard 
  Output)成为另一行程之标准输入的方法;Named pipe 
  就如同先前讨论的各项IPC机制,由於有一个识别名称,其他的行程很容易可以依照名称找过来,通讯范围不限於单机,同时,资料允许双向流通。</p>
</blockquote>

<h3>DDE</h3>

<blockquote>
  <p>如同本文第一个TwinApp这个例子,DDE也是建立在讯息通讯这个基础上的,不过它的协定内容显然严谨很多。</p>
  <p>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讯息结束对话。</p>
  <p>行程间建立DDE连接时,当Server端的资料改变时,依资料交换的频繁与Client的主动程度,其通道的形态可分为:<ul>
    <li>Cold Link:来要才有;Client端得主动要求传送资料,如果没有来要,即使Server的资料已经改变很多了,Server对Client也置之不理。</li>
    <li>Hot Link:有变就给;当资料改变时,Server端将主动通知Client改变的内容。</li>
    <li>Warm Link:更新通知;当资料改变时,Server端只对Client端告知资料改变的消息,真正的资料要等Client提出要求才会送出。</li>
  </ul>
  <p>由於DDE讯息通讯牵涉的实作细节颇多,为了使用方便起见,微软也提供DDE管理函式库(The 
  DDE Management Library, 简称 DDEML), 使用上的最大差别在於使用DDEML的程式是用Callback函数处理DDE交易(Transaction) 
  。另外,三大项目的Application改口叫做(Service name)服务。</p>
  <p>时至今日,讨论DDE的文献已不在少数,的确,DDE的使用应该是容易许多了,几乎没有一个Windows程式开发工具不提供一些元件或类别让程式员更方便制作DDE 
  Server或Client程式。当然,如果你的需求只是在行程间通知某些消息,自行设计一套讯息通讯协定倒也简单得以完成任务,我想本文的第一个例子TwinApp是一个不错的提示。</p>
</blockquote>

<h3>其他的IPC技术</h3>

<blockquote>
  <p>EXE通常呼叫DLL的输出函数(exports function),某些情况下DLL也会使用EXE 
  事先预备的回呼(Callback)函数。函数呼叫这个观念与想法如果移植到行程通讯中会发生什麽事呢? 
  我的意思是说,让一个行程呼叫另一个行程的函数。Ya! 
  这就是所谓的 RPC,行程之间属於函数呼叫层级的合作。可以想见的,由於行程各有其定址空间,如同OLE,要达到 
  RPC确实需要额外标准的介面加以定义。</p>
  <p>有关IPC的技术与观念我们已经介绍得不少了,不论是讯息交换,剪贴簿,Shared 
  memory,DDE,MailSlot,Pipe等等,几乎都是资料的交换或者Client与Server「要求-回应」,叁与通讯的行讯必须对於交换的资料有一定程度的了解与处理能力。换句话说,在我们以DDE向试算表软体要求传回资料後,这份资料到底代表什麽得自己解释;同样的,如果要传入资料到试算表软体,即使透过现成元件的帮忙,仍然必须对试算表软体有基本的认识。</p>
  <p>话说回来了,只有试算表自己最清楚资料代表什麽,不是吗?那麽,由它来处理资料应该才是适当的人选,强以外部程式去操作总有外行人指导内行人的遗憾。利用OLE技术将应用程式整合在一起工作确实是比较合理的作法,如果COM物件可以像电子IC一样安插进我们的程式与我们的程式一同工作,那这种我们称之为OLE 
  Control(ActiveX),距离拉大到网路上,DCOM这个名词你一定听说过.</p>
  <p>想想看,终於我们可以用甲公司的统计图表元件,然後用乙公司的元件将图表传真出去,这样窗景真是美好。窗子确实只提供局部的风景,但是加装了望远镜的窗子可是一个天文台,加了风铃的窗子所提供的就不只是风景了,还有悦耳的声音。</p>
  <p>不论是RPC或OLE,我想这都是属於本文应该讨论但肯定是来不及讨论的,这两个主题甚至以单篇文章来谈都不怎麽够用。事实上,有些地方(例如DDE这一节)我也没有提到技术方面的实作细节,碍於篇辐(这篇文章已经太长了) 
  日後我们会在本专栏继续以专文介绍RPC等主题。关於以Winsock作为IPC通讯机制这部分,本专栏的前一篇文章「走! 
  让我们上BBS聊天去」才刚说明过,在此就不再重覆了。</p>
</blockquote>

<h3>应用IPC到你的程式中</h3>

<blockquote>
  <p>各项IPC的技术往往以各种方式组合在一起。例如本文提供的DemoSMem范例程式就同时用了ShareMem交换资料,同步机制则采用Mutex与Event。情况并不如想像中的复杂:既是行程通讯,那必然是两个以上行程之间的事,既是分开的,中间一定有介面存在,定义这个介面的具体内容就是所谓的协定,留意资料交换的位置与方式,需要协调避让的采用合适的同步控制加以处理。这些重点把握住了,应该心 
  就已经有数了。</p>
  <p>面对各式各样的技术时,如果你正考虑应用IPC到你的程式中,首先得正视自己的需求,不妨提出类似以下的问题问问自己,最好将之写下来 
  <ul>
    <li>是否真的需要跨行程处理,成效何在?</li>
    <li>技术实作的难易程度与所需付出的成本</li>
    <li>资料的流向是单向或双向,需不需反馈(feedback)的控制查核</li>
    <li>这些工作只在单机完成,或者需要连上网路,范围只在公司内部区域网路或者是广域网路</li>
    <li>叁与通讯的行程最多与平均的数量是多少?</li>
    <li>只在一种作业环境,或者可能同时要满足不同的作业平台</li>
    <li>执行效能( performance)是不是关键需求.</li>
    <li>应用程式使用 GUI 介面或者 console mode</li>
  </ul>
  <p>接下来开始比较各项IPC的特性,哪些是与你列出的需求相符合的,有没有哪些限制是你必须要排除而避免使用的,各项IPC经过与先前写下的需求交叉评比的结果,积分高的自然是脱颖而出。最後,事情如果能简单解决是最好,开发时程缩短成本自然降低,而且日後维护容易。</p>
</blockquote>

<h3>结语</h3>

<blockquote>
  <p>技术是不断推陈出新的,当各式各样的IPC机制提出时,回顾行程之所以开始通讯合作的初衷是有必要的,唯有回到最初原始的简单需求,才能看出技术演进过程的缘由与其修正的价值,不断的变易之中我们可以粹化出一些不变的原则与观念,而这些原则应该是与最初的需求互相吻合的。</p>
  <p>以IPC这麽大的题目只写一篇文章是件很痛苦的事,我不清楚有多少读者会期待以一篇文章能将IPC的技术细节讲清楚,不过已尽我所能的交待来龙去脉。观念与说理太占篇幅,大部分的技术细节是隐藏在范例的原始程式中,这些程式日後如有修改或加强,您可以在我的网站(http://www.chih.com)找到更新後的版本,对於本文如有任何意见或评论,也欢迎您E-mail与我联络, 
  来信请寄wolfgang@ms2.hinet.net <a href="mailto:或chien@chih.com">或chien@chih.com</a>。</p>
</blockquote>

<hr>

<p>叁考资料 

<ul>
  <li>Charles Petzold, Programming Windows 95</li>
  <li>Jim Beveridge &amp; Robert Wiener着, 侯俊杰译, Win32多绪程式设计, 
    Multithreading Application in Win32</li>
  <li>MSDN Library CD, 1997/7, SDK Documentation / Platform SDK / Windows base services / 
    Interprocess Communication</li>
</ul>
</body>
</html>

⌨️ 快捷键说明

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