找回密码
 注册
搜索
查看: 4820|回复: 0

[收藏]用完成端口开发大响应规模的Winsock应用程序(2)

[复制链接]
发表于 2005-7-31 16:22:14 | 显示全部楼层 |阅读模式
  Windows NT和Windows 2000的套接字架构
9 \, j' j1 x# J# E0 B! G) s2 L" K. m$ {7 D2 r, y
对于开发大响应规模的Winsock应用程序而言,对Windows NT和Windows 2000的套接字架构有基本的了解是很有帮助的。6 @, K, F  F% T2 y+ W7 X

4 g+ {. ^8 L+ r2 L1 B5 _与其它类型操作系统不同,Windows NT和Windows 2000的传输协议没有一种风格像套接字那样的、可以和应用程序直接交谈的界面,而是采用了一种更为底层的API,叫做传输驱动程序界面(Transport Driver Interface,TDI)。Winsock的核心模式驱动程序负责连接和缓冲区管理,以便向应用程序提供套接字仿真(在AFD.SYS文件中实现),同时负责与底层传输驱动程序对话。2 C, U+ b" p- z; w

, T7 k6 b3 D! N" |, S* A3 K4 e6 L- Q谁来负责管理缓冲区?
- l, z* P& m4 H8 ~( t* O9 r; B3 F% \9 ^1 w- `" J; U# {1 D* A+ K2 x: q
正如上面所说的,应用程序通过Winsock来和传输协议驱动程序交谈,而AFD.SYS负责为应用程序进行缓冲区管理。也就是说,当应用程序调用send()或WSASend()函数来发送数据时,AFD.SYS将把数据拷贝进它自己的内部缓冲区(取决于SO_SNDBUF设定值),然后send()或WSASend()函数立即返回。也可以这么说,AFD.SYS在后台负责把数据发送出去。不过,如果应用程序要求发出的数据超过了SO_SNDBUF设定的缓冲区大小,那么WSASend()函数会阻塞,直至所有数据发送完毕。* O* X6 G+ S$ V- c3 T5 d' ?6 d/ o+ H
% l! r9 x2 T/ U% D7 y/ M1 z
从远程客户端接收数据的情况也类似。只要不用从应用程序那里接收大量的数据,而且没有超出SO_RCVBUF设定的值,AFD.SYS将把数据先拷贝到其内部缓冲区中。当应用程序调用recv()或WSARecv()函数时,数据将从内部缓冲拷贝到应用程序提供的缓冲区。
' A- r2 Z* q2 }+ Y" U8 s( X  x
  E8 f6 s* ~' W, E% P( a1 K多数情况下,这样的架构运行良好,特别在是应用程序采用传统的套接字下非重叠的send()和receive()模式编写的时候。不过程序员要小心的是,尽管可以通过setsockopt()这个API来把SO_SNDBUF和SO_RCVBUF选项值设成0(关闭内部缓冲区),但是程序员必须十分清楚把AFD.SYS的内部缓冲区关掉会造成什么后果,避免收发数据时有关的缓冲区拷贝可能引起的系统崩溃。; h1 C7 L9 c! Y7 v  E

5 F" m# E" r2 N0 s举例来说,一个应用程序通过设定SO_SNDBUF为0把缓冲区关闭,然后发出一个阻塞send()调用。在这样的情况下,系统内核会把应用程序的缓冲区锁定,直到接收方确认收到了整个缓冲区后send()调用才返回。似乎这是一种判定你的数据是否已经为对方全部收到的简洁的方法,实际上却并非如此。想想看,即使远端TCP通知数据已经收到,其实也根本不代表数据已经成功送给客户端应用程序,比如对方可能发生资源不足的情况,导致AFD.SYS不能把数据拷贝给应用程序。另一个更要紧的问题是,在每个线程中每次只能进行一次发送调用,效率极其低下。
+ R: ]1 C3 s7 \+ a" e  I! @1 ~) W6 g3 o* U# h: `- s5 }; c# E) Z6 Q4 A
把SO_RCVBUF设为0,关闭AFD.SYS的接收缓冲区也不能让性能得到提升,这只会迫使接收到的数据在比Winsock更低的层次进行缓冲,当你发出receive调用时,同样要进行缓冲区拷贝,因此你本来想避免缓冲区拷贝的阴谋不会得逞。( |; S( v8 |- V: n& r+ _( ^3 a

- [/ ]$ P' a; r8 L4 J现在我们应该清楚了,关闭缓冲区对于多数应用程序而言并不是什么好主意。只要要应用程序注意随时在某个连接上保持几个WSARecvs重叠调用,那么通常没有必要关闭接收缓冲区。如果AFD.SYS总是有由应用程序提供的缓冲区可用,那么它将没有必要使用内部缓冲区。% o% O2 G( ]' ]1 e. U( {% A
- c- H/ a3 b; r4 s" T6 A
高性能的服务器应用程序可以关闭发送缓冲区,同时不会损失性能。不过,这样的应用程序必须十分小心,保证它总是发出多个重叠发送调用,而不是等待某个重叠发送结束了才发出下一个。如果应用程序是按一个发完再发下一个的顺序来操作,那浪费掉两次发送中间的空档时间,总之是要保证传输驱动程序在发送完一个缓冲区后,立刻可以转向另一个缓冲区。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|宁德市腾云网络科技有限公司 ( 闽ICP备2022007940号-5|闽公网安备 35092202000206号 )

GMT+8, 2026-8-13 21:35 , Processed in 0.018869 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表