Microsoft Windows NT 、Windows 2000 、Windows 95和Windows 98 (含第二版)—但
不包括Windows CE—提供了一种简单的单向“进程间通信”(interprocess communication,
I P C )机制。这个机制的名字非常古怪,叫作“邮槽”(M a i l s l o t )。用最简单的话来说,通过
邮槽,客户机进程可将消息传送或广播给一个或多个服务器进程。在同一台计算机的不同进
程之间,或在跨越整个网络的不同计算机的进程之间,协助进行消息的传输。用邮槽来开发
应用程序是一件非常简单的事情,不要求对T C P / I P或I P X这样的基层网络传送协议有着非常深
入的了解。由于邮槽是围绕一个广播通信体系设计出来的,所以当然不能指望能通过它实现
数据的“可靠”传输。然而,在某些特殊类型的网络编程环境中,假如对数据传输的可靠性
要求不高,那么邮槽仍然是一种非常有价值的技术。
例如,要想在自己办公室的所有人员之间建立一个简单的传信系统,便可考虑用邮槽来
设计这个程序。想象自己的办公室环境拥有大量工作站。恰巧,办公室目前苏打短缺。每隔
几分钟,每名工作站用户都有兴趣知道苏打机里还剩下多少可乐。利用邮槽,便可很轻易地
设计出这种程序。我们可简单地编制一个邮槽客户端应用,用它监视苏打数量,并以五分钟
为周期,将剩余的可乐数量广播给每一名感兴趣的工作站用户。由于邮槽并不能担保广播消
息的可靠传输,所以有些工作站用户也许收不到所有的更新通知。但在这种情况下,少数的
传输失败并不是个问题,因为消息每隔五分钟便会发送一遍,所以即使偶尔出错,收到信息
的频率也相当高,足以让工作站用户跟上目前的最新情况。
邮槽最大的一个缺点便是只允许从客户机到服务器,建立一种不可靠的单向数据通信。
而另一方面,邮槽最大的一个优点在于,它们使客户机应用能够非常容易地将广播消息发送
给一个或多个服务器应用。
本章将向大家解释如何开发一个实际的邮槽客户机/服务器应用。在深入解释消息的大
小问题之前,首先要介绍邮槽的一系列命名规范,它们对邮槽的总体行为进行着控制。接下
来,我们将详细讲述如何开发一个基本的客户机/服务器应用。在本章结束时,则会告诉大
家邮槽一些已知的问题,以及存在的各种局限,并提出相应的解决方案。
3.1 邮槽实施细节
邮槽是围绕Wi n d o w s文件系统接口设计出来的。客户机和服务器应用需要使用标准的
Wi n 3 2文件系统I / O (输入/输出)函数,比如R e a d F i l e和Wr i t e F i l e等等,以便在邮槽上收发数
据,同时利用Wi n 3 2文件系统的命名规则。邮槽必须依赖Wi n d o w s重定向器,通过一个“邮槽
文件系统”(Mailslot File System, MSFS ),来创建及标识邮槽。第2章已对Wi n d o w s重定向器
进行了比较详细的说明。
3.1.1 邮槽的名字
对邮槽进行标识时,需遵守下述命名规则:
\ \ s e r v e r \ M a i l s l o t \ [ p a t h ] n a m e
请将上述字串分为三段来看:\ \ s e r v e r 、\ M a i l s l o t和\ [ p a t h ] n a m e 。第一部分\ \ s e r v e r对应于
服务器的名字,我们要在上面创建邮槽,并在在上面运行服务器程序。第二部分\ M a i l s l o t是一
个“硬编码”的固定字串,用于告诉系统这个文件名从属于M S F S 。而第三部分\ [ p a t h ] n a m e则
允许应用程序独一无二地定义及标识一个邮槽名。其中,“p a t h ”代表路径,可指定多级目录。
举个例子来说,对一个邮槽进行标识时,下面这些形式的名字都是合法的(注意 M a i l s l o t不得
变化,必须原文照输,亦即所谓的“硬编码”):
\ \ O r e o \ M a i l s l o t \ M y m a i l s l o t
\ \ Te s t s e r v e r \ M a i l s l o t \ C o o l d i r e c t o r y \ F u n t e s t \ A n o t h e r m a i l s l o t
\ \ . \ M a i l s l o t \ E a s y m a i l s l o t
\ \ * \ M a i l s l o t \ M y s l o t
服务器字串部分可表示成一个小数点(.)、一个星号(*)、一个域名或者一个真正的服务
器名字。所谓“域”,其实就是一系列工作站和服务器的组合,它们共用一个相同的组名。本
章稍后,在讲到一个简单的客户机的细节时,还会就邮槽名字作深入探讨。
由于邮槽要依赖Wi n d o w s文件系统服务在网上来创建和传输数据,所以接口是“与协议
无关”的。编制自己的应用程序时,便不必关心基层网络传送协议的细节,不必知道它在一
个网络中如何在进程之间建立通信。邮槽通过一个网络与计算机进行远程通信时, Wi n d o w s
文件系统服务需要依赖Wi n d o w s重定向器,使用“服务器消息块”(S M B )协议,将数据从客
户机传给服务器。消息通常是通过“无连接”传输方式来发送的,但亦可强迫 Wi n d o w s重定
向器在Windows NT和Windows 2000上使用“面向连接”的传输方式。至于具体采用哪种方式,
要由消息的长度决定。
3.1.2 消息的长度
邮槽通常用“数据报”(D a t a g r a m )在网络上传递消息。数据报实际是一些小数据包,只
不过要以“无连接”的形式,通过网络进行传输。“无连接”意味着每个数据包在发给接收者
之后,不要求对方提供包的收到确认信息。显然,这是一种“不可靠”的数据传输,因为无
法保证消息肯定能正确送达。然而,通过无连接传输,我们确实可将消息从一个客户机广播
给多个服务器。当然,上述情况也有例外。在Windows NT和Windows 2000 中,假如消息的长
度超过4 2 4个字节,便会发生这种例外。
在Windows NT和Windows 2000 中,若消息长度超过4 2 6个字节,便必须在一个S M B会话
之上,通过一种“面向连接”的协议进行传输,而不再采用无连接的“数据报”形式。这样
一来,在消息较大的情况下,便可保证它们的稳定、高效传输。然而,此时再也不能将一条
消息从客户机广播给多个服务器。对于“面向连接”的传输来说,它必然是一种“一对一”
通信:一个客户机对一个服务器!在不同的进程之间,使用“面向连接”的传输方式,往往
可保证数据传输的可靠性。但在Windows NT和Windows 2000 中,邮槽接口却不能保证一条消
息肯定能够写入一个邮槽。举个例子来说,假如从客户机向服务器送出一条较大的消息,但
指定的服务器在网络中并不存在,那么邮槽接口不会告诉你的客户机应用,数据到服务器的
投递已经失败。由于Windows NT和Windows 2000要根据消息的长度,来更改它们的传输方法,
所以假定一台机器运行的是Windows NT或Windows 2000 ,而另一台机器运行的是Windows 95
或者Windows 98 ,便会面临两种系统在沟通上的困难。
Windows 95和Windows 98只以“数据报”的形式来传送消息,无论消息长度如何。假如
Windows 95 或Windows 98 客户机试图将一条长度超过4 2 4字节的消息传给Windows NT 或
Windows 2000服务器,Windows NT和Windows 2000便会只接受头4 2 4个字节,剩下的数据会
被无情地“砍掉”。换言之,Windows NT和Windows 2000要求更大的消息通过一个“面向连
接”的S M B会话进行传输。
消息从Windows NT或Windows 2000客户机传向Windows 95或Windows 98服务器时,也
存在着类似的问题。请记住,Windows 95和Windows 98只通过数据报接收数据。由于对超过
4 2 6个字节的消息来说,Windows NT和Windows 2000不会通过数据报来传输数据,所以在这
种情况下,Windows 95和Windows 98不能从这些客户机收到消息。在表3 - 1中,我们为大家详
细总结了这种消息长度上的限制。
注意 Windows CE 已从表3-1中剔除出去了,因为它并未提供邮槽编程接口。另外要注
意的是,由于Windows NT和Windows 2000 重定向器的限制,长度为4 2 5或4 2 6字节的消
息未在此表列出。
表3-1 邮槽消息的长度限制
传输方向 通过数据报进行“无连接”传输 进行“面向连接”的传输
Windows 95或Windows 98 消息长度高达6 4 K B 不支持
- > Windows 95或Windows 98
Windows NT或Windows 2000 消息长度必须为4 2 4字节或以下 消息必须大于4 2 6个字节
- > Windows NT或Windows 2000
Windows NT或Windows 2000 消息长度必须为4 2 4字节或以下 不支持
- > Windows 95或Windows 98
Windows 95或Windows 98 消息长度必须为4 2 4字节或以下; 不支持
- > Windows NT或Windows 2000 多余的字节会被截去
对Windows NT和Windows 2000这两种网络操作系统来说,还有另一项限制值得我们注
意,因为它会对数据报数据的传输产生影响。 Windows NT 和Windows 2000 重定向器不能
收发长度正好为4 2 5 或4 2 6 字节的一条数据报消息。例如,假定我们从 Windows NT 或
Windows 2000 客户机向Windows 95 、Windows 98 、Windows NT或Windows 2000服务器发
送这样的一条消息,Windows NT 重定向器会在消息发给目标服务器之前,将其长度截短为
4 2 4字节。
要想保证各种Wi n d o w s平台之间能够完全正常地通信,强烈建议将消息长度限制在4 2 4字
节,或者更短。如果进行面向连接的传输,可考虑使用命名管道,而不是简单的邮槽。命名
管道将在第4章讨论。
3.1.3 应用程序的编译
用Microsoft Visual C++编制一个邮槽客户机或服务器应用程序时,必须在程序文件中将
Wi n b a s e . h这个包容文件包括在内。假如已经包含了Wi n d o w s . h (大多数应用程序都会这样),
那么亦可将Wi n b a s e . h省去。此外,应用程序也要负责建立与K e r n e l 3 2 . l i b 的链接,这通常需要
用Visual C++链接器标志进行配置。
3.1.4 错误代码
开发邮槽客户机和服务器应用时,所有Win32 API 函数(C r e a t e F i l e和C r e a t e M a i l s l o t除外)
在调用失败的情况下,都会返回 0值。C r e a t e F i l e和C r e a t e M a i l s l o t 这两个A P I 却会返回
I N VA L I D _ H A N D L E _ VA L U E (无效句柄值)。若这些A P I函数调用失败,应用程序随即应调用
G e t L a s t E r r o r函数,来接收与此次失败有关的特殊信息。至于所有错误代码的一个完整列表,
大家可参考本书附录C提供的标准Wi n d o w s错误代码列表,或者直接查询Wi n e r r o r. h这个头文
件。
3.2 基本客户机/服务器
如前所述,邮槽建立了一个简单的客户机/服务器设计体系。在这个体系中,数据只能
从客户机传到服务器,数据通信是单向进行的。服务器进程的职责是创建一个邮槽,而且是
能从邮槽读取数据的唯一一个进程。邮槽客户机进程则负责打开邮槽的“实例”,该进程是能
够向其中写入数据的唯一一种进程。
3.2.1 邮槽服务器的详情
若想实现一个邮槽,要求开发一个服务器应用,来负责邮槽的创建。下述步骤解释了如
何编写一个基本的服务器应用:
1) 用CreateMailslot API函数创建一个邮槽句柄。
2) 调用ReadFile API 函数,并使用现成的邮槽句柄,从任何客户机接收数据。
3) 用C l o s e H a n d l e这个A P I函数,关闭邮槽句柄。
可以看出,要开发一个邮槽服务器程序,只需使用极少的 A P I 调用。服务器进程是用
C r e a t e M a i l s l o t这个A P I调用来创建邮槽的。定义如下:
其中,第一个参数l p N a m e指定邮槽的名字。名字的格式如下:
\ \ . \ M a i l s l o t \ [ p a t h ] n a m e
要注意的是,服务器的名字用一个小数点来表示,亦即服务器就是本地机器。这样做是
很有必要的,因为我们不能在远程计算机上创建邮槽。在l p N a m e参数中,名字必须以一种独
一无二的形式表达。可将它设为一个独立的名字,也可以在它前面加上一个完整的目录路径。
n M a x M e s s a g e S i z e参数定义的是可写入邮槽的一条消息的最大长度(以字节为单位)。假
如客户机写入的字节数多于n M a x M e s s a g e S i z e的设置,服务器便不会接收这条消息。若将它的
值设为0,服务器便会接收任意长度的消息。
在一个邮槽上,读操作可以等待或不等待这两种模式进行,具体由 l R e a d Ti m e o u t参数决
定。它以毫秒为单位,指定了读操作需要等候进入消息的时间。若将它的值设为
M A I L S L O T _ WA I T _ F O R E V E R,那么在进入的数据可以读取之前,读操作便会无限期地等待
下去。若设为 0 ,读操作就会立即返回。本章稍后,还会就读操作的详情进行探讨。