第二部分Winsock API
 
 Wi n s o c k是网络编程接口,而不是协议。它从U n i x平台的B e r k e l e y(B S D)套接字方案借鉴了许多东西,后者能访问多种网络协议。在Wi n 3 2环境中,Wi n s o c k接口最终成为一个真正的“与协议无关”接口,尤其是在Winsock 2发布之后。
本部分开始之前,我们假定大家已具备了Wi n s o c k(或B S D套接字)的基本知识,而且多少熟悉一些客户机/服务器的Wi n s o c k基本知识。

第5章网络原理和协议

建立Winsock 2规范的主要目的是提供一个与协议无关的传送接口。

5.1 协议的特征
本章第一小节着重讲解目前常用网络传送协议的一些基本特征。通过这里的学习,大家可掌握与协议行为类型有关的一些背景知识。同时,作为程序员,可大致知道特定协议在程序中的行为方式。

5.1.1 面向消息
对每个离散写命令来说,如果传送协议把它们(而且只有它们)当做一条独立的消息在网上传送,我们就说该协议是面向协议的。同时,还意味着接收端在接收数据时,返回的数据是发送端写入的一条离散消息。接收端不能得到更多的消息,仅此而已。比如,在图5 - 1中,
左边的工作站向右边的工作站提交了三条分别是1 2 8、6 4和3 2字节的消息。作为接收端的工作站发出三条读取命令,缓冲区是2 5 6个字节。后来的各次调用返回的分别是1 2 8、 6 4 和3 2个字节。第一次读取调用不会将这所有的三个数据包都返回,即使这些数据包已经收到也如此。这称为“保护消息边界”(preserving message boundaries),,一般出现在交换结构化数据时。
网络游戏是“保护消息边界”的较好范例。每个玩家均向别的玩家发出一个带有地图信息的数据包。这种通信后面的代码很简单:一个玩家请求一个数据包,另一个玩家又准确地从别的玩家处获得一个地图信息数据包。

无保护消息边界的协议通常称作“基于流的协议”。大家要知道“基于流的协议”这一术语常用来指代附加特性。流服务的定义是连续的数据传输;不管消息边界是否存在,接收端都会尽量地读取有效数据。对发送端来说,意味着允许系统将原始消息分解成小消息或把几条消息积累在一起,形成一个较大的数据包。对接收端来说,则是数据一到达网络堆栈,
网络堆栈就开始读取它,并将它缓存下来等候进程处理。在进程请求处理大量数据时,系统会在不溢出为客户请求提供的缓冲区这一前提下,尽量返回更多的数据。在图5 - 2中,发送端提交了三个数据包:分别是1 2 8、6 4和3 2个字节;但是,本地系统堆栈自由地把这些数据聚合在一起,形成一个大的数据包。这种情况下,重组后的2个数据包就会一起传输。是否将各个独立的数据包累积在一起受许多因素的影响,比如最大传输单元或N a g l e算法。在T C P / I P中,在将积累起来的数据发到线上之前, N a g l e算法在等候数据积累的主机中进行。
在需要发送的数据积累到一定数量或预定时间已超过之前,这个主机会一直等下去。实施N a g l e算法时,主机的通信方在发送主机确认之前,会等一等外出数据,主机的通信方就不必发送一个只有确认的数据包。发送小数据包不仅没有多少意义,而且还会徒增错误检查和确认,相当烦人。
在接收端,网络堆栈把所有进来的数据包聚集在一起,归入既定进程。我们来看看图5 - 2。
如果接收端执行一次2 5 6字节缓冲区的读取,系统马上就会返回2 2 4个字节。如果接收端只要求读取2 0个字节,系统就会只返回2 0个字节。

伪流
伪流( p s e u d o - s t r e a m)这个术语常用于某种系统中,该系统使用的协议是基于消息的,
发送的数据分别在各自独立的数据包内,接收端读取并把消息缓存在一起,  这样,接收应用
程序便可读取任意大小的数据块。把图5 - 1中的发送端和图5 - 2中的接收端结合起来,便可说明
伪流的工作原理。发送端必须分别发送各自独立的数据包,但接收端可以对收到的数据包自
由组合。一般情况下,可把伪流视作一个普通的“面向流的协议”。


5.1.2 面向连接和无连接
通常情况下,一个协议提供面向连接的服务,或提供无连接的服务。面向连接的服务中,
进行数据交换之前,必须与通信方建立一条路径。这样既确定了通信方之间存在路由,又保证了通信双方都是活动的、都可彼此响应,但其特点是在通信双方之间建立一个通信信道需要很多开支。除此以外,大部分面向连接的协议为保证投递无误,可能会因为执行额外的计算来验证正确性,因此,进一步增加开支。而无连接协议却不保证接收端是否正在收听。无连接服务类似于邮政服务:发信人把信装入邮箱即可。至于收信人是否想收到这封信或邮局是否会因为暴风雨未能按时将信件投递到收信人处等等,发信人都不得而知。


5.1.3 可靠性和次序性
在设计用于特定协议的应用程序来说,可靠性和次序性是我们必须了解的最具决定性的特性。大多数情况下,可靠性和次序性与协议是无连接的,还是面向连接的密切相关。

5.1.4 从容关闭
从容关闭只出现在面向连接的协议中。在这种关闭过程中,一方开始关闭通信会话,但另一方仍然可以读取线上或网络堆栈上已挂起的数据。如果面向连接的协议不支持从容关闭,
只要其中一方关闭了通信信道,都会导致连接立即中断,数据丢失,接收端不能读取数据这些情况出现。

5.1.5 广播数据
广播数据即数据从一个工作站发出,局域网内的其他所有工作站都能收到它。这一特征
适用于无连接协议,因为L A N上的所有机器都可获得并处理广播消息。。一般情况下,路由器都不会传送广播包。  

5.1.6 多播数据
多播是指一个进程发送数据的能力,这些数据即将由一个或多个接收端进行接收。进程加入一个多播会话的方法和采用的基层协议有关。视频会议应用常常使用多播。

5.1.7 服务质量
服务质量( Q o S)是应用的一种能力,用以请求针对专门用途分配特定的带宽。

5.1.8 部分消息
部分消息只用于面向消息的协议。

5.1.9 路由选择的考虑
一个重要考虑就是协议是否可路由。如果协议可路由,就可在两个工作站之间建立一条成功的通信路径(要么是面向连接的回路,要么是数据报的数据路径),不管这两个工作站之间存在的网络硬件是什么。路由器不对发自非路由协议的数据包进行转发,即便数据包的既定目的地在其连接的子网上。

5.2 支持的协议
Wi n 3 2平台提供的最有用的特征之一是能够同步支持多种不同的网络协议。
利用Wi n s o c k编程接口的好
处之一是因为它是一个与协议无关的接口。不管使用的是哪一种协议,它们的操作大多数是
相通的。

要想获得系统中安装的网络协议的相关信息,调用这个函数W S A E n u m P r o t o c o l s即可,
打开Winsock在可以调用一个Wi n s o c k函数之前,必须先加载一个版本正确的Wi n s o c k库。Wi n s o c k
启动例程是W S A S t a r t u p,它的定义是:
int WSAStartup(WORD wVe r s i o n R e q u e s t e d , L P W S A D ATA lpWSAData)
第一个参数是准备加载的Wi n s o c k库的版本号。就目前的Wi n 3 2平台而言,Winsock 2
库的最新版本是2 . 2。唯一的例外是Windows CE,它只支持Winsock 1.1版。如果需要
Winsock 2.2版,指定这个值( 0 x 0 2 0 2)或使用宏M A K E W O R D ( 2 , 2 )即可。高位字节指定
副版本,而低位字节则指定主版本。
第二个参数是W S A D ATA结构,它是调用完成之后立即返回的。W S A D ATA包含了W S A S t a r t u p加载的关于Wi n s o c k版本的信息。
大致说来,在W S A D ATA结构中,返回的唯一有用的信息是w Ve r s i o n和w H i g h Ve r s i o n。
属于最大套接字和最大U D P长度的条目应该从自己正在使用的特定协议目录条目中获取。

在结束Wi n s o c k库,而且不再需要调用任何Wi n s o c k函数时,会卸载这个库,并释放资源。这个函数的定义是:
int WSACleanup (void);
记住,每次调用W S A S t a r t u p,都需要调用相应的W S A C l e a n u p,因为每次启动调用都
会增加对加载Winsock DLL的引用次数,它要求调用同样多次的W S A C l e a n u p,以此抵消
引用次数。

5.4 Windows套接字

。所谓套接字,就是一个指向传输提
供者的句柄。Wi n 3 2中,套接字不同于文件描述符,所以它是一个独立的类型—S O C K E T。
套接字是由两个函数建立的:
SOCKET WSASocket(int af,
         int type,
         int protocol,
         LPWSAPROTOCOL_INOF lpProtocolInfo,
         GROUP g,
         DWORD dwFlag
         );
SOCKET socket(int af,
       int type,
       int protocol
       );
第一个参数a f,是协议的地址家族。比如,如果想建立一个U D P或T C P套接字,可用常量A F _ I N E T来指代互联网协议( I P)。
第二个参数t y p e,是协议的套接字类型。套接字的类型可以是下面五个值:
 S O C K _ S T R E A M、S O C K _ D G R A M、S O C K _ S E Q PA C K E T、S O C K _ R AW和S O C K _ R D M。
第三个参数是p r o t o c o l。指定的地址家族和套接字类型有多个条目时,就可用
这个字段来限定使用特定传输。

最后两个W S A S o c k e t标志很简单。组参数始终为0,因为目前尚无可支持套接字组的
Wi n s o c k版本。要指定一个或多个下列标志,可用d w F l a g s参数:
■ W S A _ F L A G _ O V E R L A P P E D
■ W S A _ F L A G _ M U LT I P O I N T _ C _ R O O T
■ W S A _ F L A G _ M U LT I P O I N T _ C _ L E A F
■ W S A _ F L A G _ M U LT I P O I N T _ D _ R O O F
■ W S A _ F L A G _ M U LT I P O I N T _ D _ L E A F
第一个标志W S A _ F L A G _ O V E R L A P P E D,用于指定这个套接字具备重叠I / O(是适用于
Wi n s o c k的可能实现的通信模式之一)。这个主题将在第8章详细讨论。调用s o c k e t建立一个套
接字时, W S A _ F L A G _ O V E R L A P P E D便是默认设置。一般说来,在使用W S A S o c k e t时,最好
始终保持设定该标志。后面四个标志用于处理多播套接字。


原始套接字
利用W S A S o c k e t建立套接字时,可向函数调用传送一个W S A P R O TO CO L _ I N F O结构,以
定义准备建立的那个套接字的类型;尽管如此,还是可建立一些套接字类型(在传输提供者
目录中,它们没有相应的条目)。最佳示例是I P协议下的原始套接字。原始套接字一种通信,
允许你把其他协议封装在U D P数据包中,比如说“互联网控制消息协议”(I C M P)。I C M P的
目的是投递互联网主机间的控制、错误和信息型消息。由于I C M P不提供任何数据传输功能,
因此不能把它与U D P或T C P同等看待,但它和I P本身属于同一个级别。

Winsock API安装在“会话层”和“传送层”之间。

5.6 选择适当的协议
T C P / I P就是首选协议之一,至少从支持能力和微软的赞助这一角度来看,是
这样的

5.7 小结
通过本章的学习,大家已了解为应用程序选择网络传输时应该知道的基本特性。在为指100计计第二部分附Winsock API
下载定的协议开发成功的网络应用程序时,了解这些特性是至关重要的。我们还有计划地深入探讨了如何获得安装在系统中的传输提供者列表和如何查询特定属性。最后,我们还学习了如何为指定的传输建立套接字,方法是为W S A S o c k e t或s o c k e t函数指定正确的参数,再利用
W S A E n u m P r o t o c o l s查询目录条目以及通过W S A P R O TO C O L _ I N F O结构,把函数投递到W S A S o c k e t。下一章,我们将进一步探讨各主要协议的定址方法。

 

Posted on 2006-09-06 19:00 艾凡赫 阅读(395) 评论(0)  编辑 收藏 引用 所属分类: 网络编程

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理