内容:
为什么要采用 DSO
很重要的版本问题
模块的工作原理
编译 Apache 支持 DSO
开发 DSO
部署 DSO
实例向导
参考资料
关于作者
在 linux 专区还有:
教程
工具与产品
代码与组件
文章
侯光敏 (wearebug@etang.com)
2003 年 1 月
kylix是linux下非常好的集成开发工具(个人认为是windows程序员转向Linux最适合的),前一段工作中使用Kylix3进行了Apache动态共享对象(DSO)的开发,在开发工作中遇到了许多的问题,经过摸索一一解决了,有些经验给大家共享,以免后来者走弯路。
为什么要采用DSO
最重要的原因是效率。Apache是模块化设计的,所以它可以加载各种各样的服务器端脚本解释器来支持动态的网页。我以前开发的是cgi,但是随着页面访问量的增大,cgi已经不看重负,我需要提高效率。由于原有的代码量很大,我基本上不可能重新写php或者jsp来代替他们,所以我选择了把最常调用的模块编译成动态共享对象(DSO).。
还有一个原因,cgi程序是短连接,不能保存用户的状态信息,如果采用常驻内存的DSO,那么这个问题也可以迎刃而解了。
很重要的版本问题
用kylix开发DSO过程中的版本问题是非常重要的。开源的Apache更新的很快,Apache 1.*版本和2.*版本的DSO格式是不一样的,一定要考虑到。Delphi6/kylix2编译出来的DSO是对应Apache 1.*版本的。我使用的是kylix3和Apache2.0.43,Borland的官方网站上说kylix3不支持Apache2 的DSO,这让我郁闷了很长时间。后来知道了Delphi7支持Apache2的消息,而Delphi7的CLX技术是跨平台的,这让我找到了解决的办法。
Delphi7的DSO2工程里要引用HTTPD2、ApacheTwoHTTP和ApacheTwoApp(DSO1对应的是HTTP、ApacheHTTP和ApacheApp),那么我就将Delphi7安装目录下源代码目录中对应的pas文件拷贝出来,存放到kylix3的源代码目录下然后编译。我查看过源代码,里面有跨平台条件编译的符号,所以这种做法是可行的。
模块的工作原理
Apache模块可以在Apache中登记它们提供函数的回叫信号。回叫是一种可以在Apache中登记的函数,Apache可以在请求进程循环中的多个阶段调用该函数。回叫通常作为进程的特殊事件处理程序登记。多数Apache为模块登记回叫函数提供的链接都是HTTP请求循环的一部分。Apache当前定义了11种请求循环阶段,模块可以登记回叫函数。它们依次为:读后请求(Post-Read)、URL翻译、头部解析、访问控制、身份验证、授权、MIME类型检查、修正(FixUp)、响应或满足、日志记录、清除。
编译Apache支持DSO
不幸的是,默认的Apache配置是不支持DSO的,所以我们必须修改配置文件然后重新编译,我是直接通过命令行完成的。这个不难,把得到的httpd*.tar.gz文件解包后,进入该目录,键入如下的命令:
./configure -enable-so
make
make install
在编译过程中如果出现了问题的话,查看一下出错的信息,一般都是没有相应的开发包造成的,把开发包装上就行了。默认安装在/user/local/apache2/目录,如果你要有别的配置要求,键入./configure -help自己看看吧。
开发 DSO
有了前面的准备工作,使用Kylix开发DSO就变得非常简单了,只需要在建立工程的时候选择生成Apache DSO,和建立CGI没有什么不同,Kylix把不同的地方透明化了。
在工程文件中还要作如下修改:
默认建立的工程文件(以webSnap工程为例):
Library Project1
Uses
WebBroker,
ApacheApp,
……
{$R *.res}
exports
apache_module name 'Project1_module'
….
….
把Uses中的ApacheApp改为ApacheTwoApp,加入HTTPD2,为什么要这么改不用我解释了吧^__^。还有一个要修改的地方是HTTPD2.pas文件,找到常量定义的地方,把这个常量MODULE_MAGIC_NUMBER_MAJOR的值改为20020903,这样Apache2才认这个DSO,切记。
由于DSO是常驻内存的,它不像cgi那样可以在进程退出时自动释放所有的资源,所以资源分配和回收的问题尤其重要。在取得数据库中的数据后一定要记得在适当的析构函数中把数据库连接关闭,建立某些堆对象使用后一定要释放内存。当然,不管开发什么样的程序,这都是一个合格程序员应该做的。
调试DSO有点麻烦,在Borland的官方网站上有介绍,但是我使用我的方法调试,你可以自己决定用什么方法。我先做一个Cgi工程调试,在入口加死循环,然后用kylix自带的进程捕获功能捕获被启动的cgi,把循环标志位置为假就可以继续单步执行了。调试完毕确认无误后建立新的DSO工程,删除工程原有的单元文件,接着把刚才cgi工程里的所有单元文件加到这个工程里来重新编译就行了。
部署DSO
当然要修改Apache的配置文件了,做linux下的开发少不了这些操作。
进入apache安装目录下的conf目录,修改httpd.conf文件,加入如下的文字:
LoadModule XXX modules/YYY.so
<Location /ZZZ>
SetHandler YYY-handler
</Location>
启动Apache后,就可以输入http://主机名/ZZZ 调用你部署的DSO了。需要注意的问题是,XXX你自己定义的Apache模块的名称,在这里你可以写Project1_module,后面跟的是模块文件的所在位置,一般都放在modules下,YYY是生成的so文件的名字,在这里应该是Project1.so。如果在启动或者运行的过程中有一些so文件找不到的话,需要在配置文件里加上SetEnv LD_LIBRARY_PATH so文件所在的路径。
实例向导
在这里我使用经典的helloWord作为实例,你可以通过这个例子走上Apache DSO开发的漫长道路。现在通过上面的讲解,我假设你已经使你的Apache支持DSO了,我们以此为起点一步一步向下走。
1 建立一个websnap工程文件,选择Apache DSO。命名为helloWorldP.dpr
2 修改源代码文件
3 修改页面文件输出helloWorld。
见下图所示。如果你要完成其他的功能,和普通的cgi是一样的。这里只是一个简单的小例子,并不完成真正的websnap工作。
4 编译这个工程
kylix的默认设置里会为你生成的DSO文件加上lib前缀,所以你可以看到在你保存工程文件的地方新生成了一个文件libhelloWordP.so,这就是生成的DSO文件。把这个文件拷贝到Apache安装目录的modules子目录下。
5 改写Apache配置文件
进入apache安装目录下的conf目录,修改httpd.conf文件,加入如下的文字:
LoadModule helloWorld_module modules/helloWorldP.so
<Location /hello>
SetHandler helloWorldP-handler
</Location>
6 兴奋的时刻到了
我说的可不夸张,当我经历了种种出错提示之后就是这种感觉。现在重启Apache,在浏览器中敲入http://你的服务器名/hello ,hello就是你在配置文件中包含在Location定位符后面的文字,不能与已经存在的其他cgi等定位重名(我曾深受其害)。如果没有问题的话,你会看到下面的东西:
就是这些了,这仅仅是个开始,接着开始你的工作吧,你会发现linux下的开发也是很有意思的。需要注意的是,在linux下大小写是敏感的,千万不要把windows下的坏习惯来过来,那样你会白白耽误很多时间。
参考资料:
* 《linux Apache Web Server管理指南》
* 你可以在这里找到更多的开发参考:http://www.thedelphimagazine.com/
* 关于linux下的开发,在IBM DeveloperWorks有很多的中文参考。
关于作者:
侯光敏,对未知事务充满好奇的程序员,飘在北京。目前使用Kylix做linux下的Web开发,也使用Java进行开发工作。我的电子邮件 wearebug@etang.com,不要发广告和垃圾邮件,求求你了