网络编程--走出完成端口的误区

网络编程--走出完成端口的误区
[版权所有:YuSheng E-mail: danscort#nbip.net  #->@ ]
最近一段日子,可以有时间到论坛看看网络编程版块了,很多关于服务器网络模型的选择,几乎有一半的人看都不看人家的去需求,直接就回用完成端口吧,我在自己的代码里用了,速度有读快之类的,看了很无语,今天有点时间,写了点个人关于完成端口的看法。

[1]为什么要在WINDOWS平台推出完成端口模型?
我们知道,LINUX为了解决SELECT或者POLL函数调用效率不够高的问题,退出了一个内核调用函数EPOLL,而WINDOWS下的完成端口更进一步,EPOLL只是在有变化的时候通知投递者,而完成端口干脆连部分变化也一起给处理了。 SELECT效率为什么不如EPOLL,这就需要操作系统知识了,因为操作系统对句柄的管理是全局的,而很多操作是通过驱动来完成的,SELECT的原理是,对SELECT指定的SOCKET队列进行循环扫描,直大发生指定变化或者超时,注意是循环,特例就是指定超时时间为0,这个时候,SELECT的效率同样是很高的,而当变化发生时,由于调度的关系,这个时候SELECT可能并没有被调度运行,导致了时间的延迟,具体请参考操作系统原理中CPU的分配策略。而引入完成端口,则通过在内核开启线程,在内核级别对需要监视的句柄进行监视,可以在驱动投递信息的第一时间发现,并立即使用内核线程进行处理,例如,TCP协议栈接收到了一个数据包,那么这个关联的句柄发生的变化会立即通知给内核对应线程,内核线程将立即处理。
换个通俗的比喻,一个厨师,被指定要同时监视10壶水的烧制,一旦水开,就立即通知,SELECT下[超时不为0],这个厨师需要从第1壶开始检查,一直到第10壶,然后从新从第1壶开始检查,直到规定时间到达或者有水烧开;而完成端口呢,则是科技进步了,我们给水壶装个感应器,当水开了,感应器就报警,然后厨师就立即知道是哪壶开了,更进一步,还可以指定水开了执行什么动作,例如冲到暖水瓶里,直到20瓶水都冲满才返回。
[2]完成端口在什么情况下是高效的选择?什么时候成为低能儿?
完成端口的高效是相对与SELECT的‘低效’而言的,但是,其实,有时候,完成端口会成为低能儿,这要看具体的应用,针对不限速度,在多连接情况下,希望最高效率发挥网络带宽优势的应用[也就是不在乎CLIENT的公平处理],或者希望能够以接近实时速度处理网络变化的[例如在线播放],完成端口是很好的选择,因为可以在第一时间处理网络事件。但是完成端口不是万能药,使用完成端口,和二进制协议,例如基于包的传输协议的处理很容易,效率也很高,但是对主流的变长文本协议,例如HTTP服务,FTP服务,EMAIL服务等,完成端口的结合,则比较困难,在网络不好的情况下,效率直线降低,为什么呢?因为TCP有个内部缓冲,在完成端口下,这个缓冲的作用被弱化了,只要有一个包到达,完成端口就执行一次从缓冲里读操作检测执行,而通常应用,一个数据段会由很多包组成,这样,内核线程需要调度很多次,而如果使用非阻塞SOCKET读,通过定时检查机制,可以避免这种内部的频繁调度,但是,由于定时并且运行在用户态而非核心态,因此无法在第一时间知道变化。这么理解呢?就好象你要发快件,在完成端口下,你只要发现有一封快件就绪,你就立即送到快递公司里去处理,而SELECT下,你发现有快件就绪,则通知快递公司,让他们的快递员有空了上门,在定时检测机制下,则是不管有多少快件就绪,反正快递公司每天上门一次。这里的快递公司,就是执行的调用者。
[3]我为什么不采用完成端口?
我写的FtpAnywhere软件,在第三次重写底层代码的时候,曾经考虑使用完成端口,毕竟MAKEDOLLAR公司大力推荐这个,但是很快发现了问题,MS自己的IIS竟然用驱动,而不是完成端口?其次,如果使用完成端口,和协议很难结合,因为国际标准的FTP协议是以回车换行为结束标记,而且指令是变长的,如果我采用完成端口,那么会面临碎片攻击导致频繁调度,例如,一个1200个字符组成的命令行,别有居心的程序,可能按每次1到5个字符发送,这样的合法攻击一多,服务器性能立即直线降低,在完成端口通知机制下,可能为了一个连接的一个指令,需要调度几百次之多,而每次调度,除了接收,还需要执行结尾判断,服务器资源将被大量合法浪费,而WINDOWS下的消息开销同样昂贵,而且有最大消息队列限制,数量超极限就出现消息丢失。而如果使用非阻塞的定时机制,则可以借助TCP本身的缓冲,避免这个问题。
[4]你是否真的需要完成端口?
不要被宣传迷惑,也不要为了片面追求所谓的高效而采用完成端口,任何一个机制,都与它自己的优点和缺点,在您确定选择完成端口前,请问问自己:
 A 我理解完成端口吗,理解TCP/IP吗,理解操作系统的内部调度机制吗?
 B 和我自己的协议应用结合容易吗?
 C 如果使用其他模型,效率差距大吗?
 D 我考虑到攻击问题了吗?
 E 将来会需要跨平台支持LINUX/BSD UNIX等平台吗?

 

 F .......

 

最后给各位推荐几本个人认为很经典的书籍

[1] UNIX网络编程 [RICHARD STEVENS版,最新版可以当参考]

[2] TCP/IP协议卷 1-3  [RICHARD STEVENS等]

[3] LINUX内核XX  名称可能不正确  作者是德国人还是美国人,忘记了,但是详细分析了LINUX下TCP/IP协议栈的实现和内核调度,看介绍就知道了,这个书很经典,分析的很详细

[4] 操作系统原理   英国MINIX作者编写的

[5] 安全编程      美国人写的,好象是什么PGP算法的作者吧

没有更多推荐了,返回首页