高级C的函数库 acl (advanced C library) 介绍
一、acl 是什么?
其实是一个很简单的问题,acl 的英文字母 advanced C library 的缩写(当然,您也可以认为是 a C library 的缩写)。也许有人会问:"现在有这么多C的函数库,为何还费这么大劲再写一个?"。的确,现在开源的 C 函数库真是太多了,比如:glib(这是一个gnome工作组开发维护的库,开始也是为了gnome界面用,后来发展成通用的 C 函数库),libevent(这是UNIX平台下一个封装了 select/poll/epoll/kquue 等的库,主要是为了应对大并发网络程序的开发),pthread-win32(这是在win32平台下按Posix接口标准写的库,其中google的 chrome 浏览器就用到了它),当然还有更为著名的 C++ 函数库 ACE(还有自称比ACE还好的C++库ICE)。每个库都有各自的特点,都能满足不同的应用需求。但是,当我在开发一个希望能跨平台的、支持常见数据算法、有很好的服务器框架、支持线程池/进程池、支持同步/异步通信、简单易用可扩展、支持HTTP协议、ICMP协议、DNS协议等的应用时,就不得不组合各个函数库,有时还得为这些库的不兼容性做些努力。
二、acl 是怎么来的?
因此写一个通用简单的 C 库就成为了一个小小的目标,开始 acl 的名字叫 util,生成的库名叫 lib_util.a,并且该库的函数大部是从 Postfix 借鉴过来的,也就是说初期没有 Postfix 就不会有 acl。Postifx 虽然只是一个邮件的 mta(现在国内的很多大的网站的MTA就是由 Postfix 修改而成,象 sohu, 263, sina, qq 等的邮件系统),但其中的函数库却设计的如此巧夺天工, 虽然是用 C 语言写成,但其设计思想却可与 C++ 媲美,Wietse Venema 不愧为世界级架构师,否则IBM也就不会请他来写 Postfix 了,在读了 Postfix 的源码后,本人将其中一些具有通用性的函数库(象vstring.c, htable.c, ring.c, etc)抽出来,构成了 lib_util.a 的主体部分。随着时间的演变, lib_util 里加的函数库越来越多,并且在与其它函数库连用时很容易造成命名冲突,因为 C 语言没有象 C++ 命名空间的概念,一般的做法都是在函数名前加 xxx 前后缀来区分。所以,是应该重新给 lib_util 起个名字的时候了,象 tcl(turbo c library), 等名字都被用过,但总觉得有点别扭,有一天突然想到用 acl 似乎也不错,嗯,advanced C library ---高级 C 库,意思是应该比 ANSI C 的标准库提供更为高级的功能。acl 名称确定下来后,于是把函数的名称都加了小写的 acl_ 前缀,结构、宏、全局定义的名称前都加了 ACL_ 前缀,确实是个不错的命名。
三、acl 的目录划分
开始时 acl 的目录规划比较简单,只有 src/ 和 include/ 两个目录,所有的源代码及头文件都分别放在这两个目录下,当然这也主要是因为 Postifx 的 util/ 目录下是通用的函数库的原因(当初就是想把 Postfix 的 util/ 下的库单独抽出来),当发现函数库越来越多时,发现将所有源代码放在同一目录下维护起来是多么地麻烦,所以想应该规划一下目录结构了,于是乎,划分了几个一级目录:stdlib/, event/, aio/, thread/ 等目录,其中在 stdlib/ 目录下还有 common/, memroy/, string/, configure/ 等二级目录。这样,acl 的体系结构算是基本形成了。现在 acl 的目录划分基本是以功能为标准的,各个目录的主要功能如下:
3.1 src 目录
3.1.1 init/ : 主要用于初始化 acl 基础库
3.1.2 stdlib/ : 是一些比较基础的功能函数库,在 stdlib/ 根目录下主要包括一些有关日志记录、网络/文件流处理、VSTRING缓冲操作等功能函数;在 stdlib/ 下还有二级目录,如下:
3.1.2.1 common/ : 该目录主要为一些常用的数据结构及算法的功能函数库,象哈希表、链表、队列、动态数组、堆栈、缓存、平衡二叉树、模式匹配树等;
3.1.2.2 memory/ : 该目录主要包含与内存操作相关的函数库,象内存基础分配与校验、内存池管理、内存切片管理等;
3.1.2.3 filedir/ : 该目录主要包含与目录遍历、目录创建等相关的库;
3.1.2.4 configure/ : 该目录主要包含配置文件的分析库;
3.1.2.5 iostuff/ : 该目录主要包含一些常用的IO操作的函数库,象读/写超时、设置IO句柄的阻塞模式等;
3.1.2.6 string/ : 该目录主要包含一些常用的字符串操作的库,提供了比标准C更灵活高效的字符串操作功能;
3.1.2.7 debug/ : 主要用于协助调试内存的泄露等功能;
3.1.2.8 sys/ : 主要是与不同操作系统平台相关的API的封装函数库;
3.1.3 net/: 是与网络操作相关的函数库,包含网络监听、网络连接、DNS查询、套接口参数设置等功能;
3.1.3.1 connect/ : 主要是与网络连接相关的函数库,包含网络连接、域套接口连接等;
3.1.3.2 listen/ : 主要是与网络监听相关的函数库,包含网络监听、域套接口监听等;
3.1.3.3 dns/ : 主要是与DNS域名查询相关的函数库,包含对 gethostbyname 等接口的封装、按RFC1035标准直接发送UDP包方式进行查询等功能;
3.1.4 event/ : 主要封装了 select/poll/epoll/kqueue/devpoll 等系统API接口,使处理网络事件更加灵活、高效、简单,另外还包含定时器接口,acl 中的很多网络应用都会用到这些接口,象 aio、master 等模块;
3.1.5 aio/ : 主要包含网络异步操作的功能函数,该套函数库在处理高并发时有非常高的效率,而且提供了比基础API更为高级的调用方式,比使用象 libevent 之类的函数库更为简单,而且是线程安全的;
3.1.6 msg/ : 主要包含了基于线程的消息事件及基于网络的消息事件功能;
3.1.7 thread/ : 主要是封装了各个OS平台下的基础线程API,使对外接口保持一致性,消除了平台的差异性,同时还提供了半驻留线程池的函数库,以及对于线程局部变量的扩展;
3.1.8 db/ : 主要是一些与数据库有关的功能库,定义了一个通用的数据库连接池的框架(并且实现了mysql的连接池实例);一个简单的内存数据库(由哈希表、链表、平衡二叉树组合而成);ZDB数据存储引擎,这是一个高效的基于数字键的存储引擎;
3.1.9 proctl/ : win32 平台下父子进程控制功能库;
3.1.10 code/ : 常见编码函数库,包括 base64编解码、URL编解码以及一些汉字字符集编码等;
3.1.11 unit_test/ : 包含有关进行 C 语言单元测试的功能库;
3.1.12 xml/:是一个流式的 xml 解析器及构造器,可以支持阻塞及阻塞式网络通信;
3.1.13 json/:是一个流式的 json 解析器及构造器,可以支持阻塞及阻塞式网络通信;
3.1.14 master/: 是在 UNIX 环境下支持多种服务器模式的服务器框架,目前主要支持多进程模式、多进程多线程模式、多进程非阻塞模式以及多进程触发器模式;
四、acl 是如何跨平台的?是如何支持WIN32平台的?
在开发 acl 库时是完全基于 linux 平台的,后来公司要做一个P2P的项目,需要在WIN32下开发客户端程序,主要需要 acl 中的 HTTP 协议通信及协议解析部分,所以为了项目需要, acl 中的HTTP协议库及HTTP协议库所依赖的一些函数库被移植至WIN32下。由此,觉得 acl 应该有一个 win32 版本,所以本人花费数周N个晚上,将 acl 库中的几乎所有函数库都移植至WIN32下(当然目前仅有master服务器框架还没移植),后来还移植至FreeBSD、Solaris(x86)上(从LINUX移植至这些UNIX平台相对容易些),主要还是在移植至WIN32平台时比较费劲,因为WIN32的API与UNIX及POSIX的真是相差太远了,感觉一点就是在WIN32下直接用API编程还是挺辛苦的,有时本来一个非常简单的IO读写,在WIN32下却需要N个参数,并且微软的API 还有一个特点,就是很多API都有一个Ex(扩展)版,看来是它们的工程师在当初设计API时发现不够用又加进去的。
另外,微软的编译器版本比较多,有VC6,VC2002,VC2003,VC2005,VC2008,现在还有VC2010,各个编译器之间还有一些差别,要想完全支持这些编译器工作量是巨大的,所以acl 目前可以用 VC6, VC2003, VC2008 编译,说起仅支持这些编译器还是有原因的,VC6做为一个老牌的编译器,存在的历史时期比较久,自 Borland 的BC被VC打败后,微软就在VC编译器无所作为了,N年未大改过VC6,说实在话,这个VC6也真是够难用的(当然现在还有许多人在用它),后来微软终于出VC2002,算是VC6的一个大版本升级,终于变得“比较”好用了,不过VC2002似乎存在不少BUGS,所以微软又推出了VC2003,这个版本本人觉得还是很不错的,可以说是VC6的终极版,因为VC2005后,微软在VC编译器的改动就比较大了,显著一点就是比较浪费系统资源了,对于象我这样用惯 vi 编辑程序的程序员,机器配置并不需要太高,而用VC2005时明显机器的CPU及内存不够用的,本人感觉 VC6, VC2002,VC2003 属于一个系列的,标准C库变动不是特别大,但到了VC2005后就变动比较多了,比如在VC2003时一般用 snprintf 就可以了,但用VC2008时,你会发现微软“自作聪明”地提示你应该用 snprintf_s ,而且多了几个参数,为了支持VC2008,acl库里还是做了不少改动。但本人还是比较偏爱VC2003,它仅不会象VC2005/VC2008那样费资源,又比VC6好用,而且没有VC2002那么多BUGS,所以 acl 库在WIN32的主推编译器是VC2003:)。
五、acl 从哪些开源软件中汲取了经验?
首先得感谢 Postfix(2002-2005本人在方标以此作为方标邮件系统的MTA模块), 里面良好的框架设计及编码风格是 acl 始终追求的;squid(2005-2007年本人在和讯改造SQUID以适应和讯的网络访问需求)/nginx,这两款HTTP代理加速软件在HTTP 协议处理方面给本人了很多启示;ircd 是一个比较“古老”的聊天服务器(2000-2002年本人在263做的263 web聊天室的后台服务器就是基于 ircd),也是本人最早接触的服务器程序,而且同 squid/nginx 一样是非阻塞通讯模式。