烽驿2009开源实时通信平台 源码获取:svn checkout http://fy2009.googlecode.com/svn/trunk/ fy2009-read-only
大型通信服务器软件通常需要管理成千上万的连接,为了在底层Socket句柄(Linux上称为描述符)上收到
数据时能快速递交给应用层连接对象,实现一种高效的以Socket句柄为Key的连接对象查找算法是绝对必要的。毫无疑问,最快的查找算法是直
接以Socket句柄为下标的连接对象数组,但该算法要求操作系统在分配Socket句柄时高度聚集,否则,将
引起对象数组的“稀疏化”,影响系统容量,甚至引起内存耗尽;退而求其次的算法应当是具有实用恰当的Hash函数的Hash Table,其优点是
允许操作系统在分配Socket句柄时相对离散,但算法效率不如上述数组下标法; 再退而求其次,STL标准
map的红-黑树也是一种选择,但在该场景,其插入和查找效率都不太理想。但究竟采用哪种算法,很大程
度上取决于操作系统分配Socket句柄的策略。笔者分别对Linux和Windows做了测试,结论如下:
Linux:
无论2.4还是2.6内核,其Socket描述符分配都是从3开始,连续递增。因为在Linux下,Socket描述符其实
就是文件描述符,和硬盘文件及其它IO设备共享取值空间,因为0,1,2分别预留给了标准输入,标准输出和
标准错误,因此Socket描述符最小从3开始,若程序在访问Socket的同时还会访问磁盘文件或其它IO设备,
将会用掉一部分文件描述符,导致Socket描述符不再连续,但所有打开的IO设备描述符加在一起,则严格
表现为连续递增。
结论:Linux下Socket描述符分配表现为高度聚集,因此,要在Linux下实现以Socket描述符为Key的连接对
象查找算法,数组下标法是当然的首选。
Windows XP:
前面的484个句柄从1952开始按4递减(如果是64位系统也许会按8递减,但仅是猜测,没有实证),其
中,644,568,536和268四个句柄跳空(不确定是否和标准输入,标准输出等有关),0被保留不用。从第485
个句柄开始,则从2052开始按4递增(2052和1952之间空100或25个句柄)。同样,打开磁盘文件也会挤占
掉Socket句柄取值。
结论:Windows下Socket句柄分配策略同样表现出聚集特性,也和磁盘文件等共享取值空间,但和Linux不
同的是,Windows下Socket句柄并不连续,而是按4递增或递减,另外,也不是单调递增,刚开始时从1952
开始递减。
结论:Windows下Socket句柄描述符分配同样表现出聚集特性,在基于Socket句柄查找连接对象时同样可以
采用数组下标法,但为了避免数组过于稀疏,最好对句柄值除以4,另外,数组尺寸则不能小于1952/4。
上述算法的缺陷是操作系统并未承诺上述分配策略不变,操作系统升级导致的分配策略变化可能引起查找
算法失效,但对于效率至关重要的Server应用,仍然值得采用,尽量通过较好的程序结构规划,以降低操
作系统升级可能引起的程序变更。而对于操作系统兼容性更重要,可适当牺牲情能的客户端应用也可考虑采用Hash Table或标准Map等查找连接对象