Apache源代码解析之主程序

本文节选自《Apache源代码解析-基于Apache0.6.5》第二章,探讨了Apache主程序httpd.c,涵盖守护进程的概念、创建过程,以及Apache的生命周期。通过理解守护进程的原理,确保Apache在Linux系统中独立运行,不受终端影响。同时,文章还预告了后续对Apache生命周期的深入讲解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

节选自《Apache源代码解析-基于Apache0.6.5》第二章。

网址:http://www.oldapache.org

论坛:http://bbs.oldapache.org

邮箱:tsingien@gmail.com


    本章介绍了httpd.c程序的相关内容。这个程序是Apache的主程序,里面包括了Apache初始化的绝大部分调用,从这个文件里面我们能大概了解Apache前期准备工作的内容。

    程序httpd.c里面涉及到Linux下c语言编程中的进程、守护进程、管道、信号量等几个重要概念,同时需要您理解Socket编程的一般流程。如果您对这些概念或流程比较陌生,请参考相关书籍。

2.1 守护进程


2.1.1什么是守护进程

 

    要理解守护进程,首先我们需要了解什么是终端。在Linux系统中,系统与用户进行交流的界面成为终端,每个从这个终端运行的程序会依附于这个终端,这个终端称为在其运行的程序的控制终端。当终端被关闭时,从这个终端运行的进程就会自动关闭。

    终端是一个用户设备,它从用户接受键盘输入,并将这些输入发送到主机,主机处理用户输入的指令,并将处理的结果现实在这个终端的屏幕上。

    Apache运行起来的时候我们不希望它依赖于某个特定的终端,否则在这个终端关闭的时候我们的Web服务也就停止了,用户就再也不能访问我们的站点。

    这时候我们就需要让Apache以守护进程的身份运行。那么什么是守护进程呢?

    简单点说,守护进程就是脱离了特定终端,在后台运行的进程。

    怎么让一个在终端上运行的程序成为守护进程呢?

2.1.2 创建守护进程

 

    创建守护进行需要主要的3步:

1. 创建子进程,父进程退出

    通过fork调用创建子进程,父进程退出。这样新创建的子进程就成了孤儿进程,会被init进程收养,成为init进程的子进程。

    从表现上看,程序立即返回,似乎程序已经运行完毕。

    但是这个子进程并没有从实质上摆脱运行其“先父”进程的终端。

2. 在子进程中创建新会话

    这里又有两个比较重要的概念,进程组和会话。

    进程组是一个或多个进程的集合,用唯一的进程组ID来标识,进程组开始时有一个组长进程,组长进程的进程ID就是组ID,组长进程可能会退出,但它的退出并不影响进程组的组ID。

    会话是一个或多个进程组的组合,通常一个会话开始于用户登录,终止于用户退出这次登录,在用户退出登陆前运行的所有进程都属于这个会话。

    或者,您是一个web程序员,那就一定用过session这个东东,其实一个会话可以理解成一个session。巧的是会话也是译自session这个单词。

    从步骤1里面我们知道,子进程从形式上脱离了其“先父”进程的终端,但实质上由于fork调用继承了父进程的会话、进程组、控制终端,所以虽然父进程退出了,但会话、进程组、终端等并没有受到影响。这就需要我们的setsid函数出马了。

    您可以通过在命令行中输入man setsid来查看对这个函数的最权威的描述。基本上这个函数有三重功效(够多的):

  • 让进程摆脱原会话的控制
  • 让进程摆脱原进程组的控制
  • 让进程摆脱原控制终端的控制

    是的,这正是我们需要的。

    是不是这样就完成了我们将程序置为守护进程的大任了呢?还没有!不只是因为我上面说需要三个步骤,主要还是因为fork调用惹的祸。

3. 修改当前工作目录

    这里需要说明一个概念,Linux文件系统的挂载和卸载。

    如果您习惯了使用windows系统,可能对这个概念没有直观的理解。比如您在windows系统里面,在光驱里面放了一张光盘,光驱开始读盘,你就可以在资源管理器里面点击光驱盘符来查看光盘里面的内容,当然,前提是光驱能正常把盘里面的内容读出来的话。

    但是在Linux系统里面就没有这么风光了,你在光驱里面放上光盘之后,并不能直接读取光盘里面的内容,还需要把光驱设备挂载(mount)到某个挂载点上,然后通过这个挂载点来浏览光驱里面的内容。使用完了之后还需要卸载(unmount)光驱。

    当然,当代的Linux会自动把光驱mount到固定的挂载点上(一般是/mnt/cdrom),这也是你能在放置完关盘后直接通过/mnt/cdrom 来访问光驱的原因。访问完了之后也可以通过图形界面里面右键菜单的弹出来结束对光驱的使用(此时系统调用了unmount指令)。

    对其它外设的使用如U盘也是同样的操作,为什么要提到挂载和卸载呢?因为fork调用埋下了另外一个隐患,就是子进程继承了父进程的当前工作目录。

    这可能造成一些问题,比如我们是通过U盘来启动的Apache(也许您根本不会这么做),或者说Apache的工作目录在后继的操作中要卸载(这是无法预 知的事情,谁也保不准哪块云彩下雨),很显然是卸载不掉的,因为“进程在运行时,当前目录所在的文件系统不能卸载”!那怎么办呢?其实方法很简单,修改当 前工作目录。

    我们可以通过调用chdir来修改当前的工作目录,这样就避免了上面提到的问题,修改到那个目录也是一个学问,可以像有人说的修改到/tmp目录,这个目录不会卸载,但我还是建议您修改到根目录,也就是/目录,这个目录如果卸载了,整个系统就没法用了。

   关于chdir的详细信息可以通过在命令行里面输入man chdir来获取。简单介绍如下:

   原型:int chdir(const char *path);

   功能:修改当前进程的工作目录到path目录。

   举例:chdir("/");

2.2 Apache生命周期

 

    main函数是整个Apache的主函数,以main函数为主线,通过跟踪main函数的调用,我们可以了解Apache的生命周期。

    如果您跟着调用的层层深入,发现阅读代码有困难,可以暂时放下,在后继章节里面,我们会根据功能模块对Apache的各个部分做一个详细、深入、详细的讲解,等您看完全书后再回来看这个图,会有一种豁然开朗的感觉。

    您可以先通过查看图2-1来对Apache的生命周期有一个感性的认识:

   

2.3 代码注释

 

    从现在开始,我们将会接触到Apache的源代码。为了方便您和下载的源代码对照查看,作者在注释时提供了对应源代码的行号。为区分行号和正常代码,行号使用浅色字体显示。

限于篇幅,注释代码部分请参看本书官网。


节选自《Apache源代码解析-基于Apache0.6.5》第二章。

网址:http://www.oldapache.org

论坛:http://bbs.oldapache.org

邮箱:tsingien@gmail.com

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值