分类: C/C++
2013-07-29 11:06:02
lighttpd版本:1.4.32
参考资料:lighttpd源码分析 by高群凯
首先分析它的main函数,弄清程序的流程。
这部分内容在server.c和server.h里面
分为两部分:监控进程或若干个工作进程(可以再配置文件中设置,仅有一个进程)
工作进程是监控进程的子进程,所以很多初始化工作在监控进程工完成,这样工作进程可以很好的继承。
下面就分两部分简单介绍下。
监控进程流程:
1.server结构体初始化
3.读取配置文件 (根据参数,如果程序运行的目的是打印配置文件或和检测配置文件,那么现在退出程序)
4.将标准输入和输出重定向到/dev/null,因为该程序用不到
5.安全性设置(不允许setuid-root用户,检查document root) 它的安全性主要体现在三个方面:
chroot(),setUID,setGID
protecting doc root
strict HTTP-header parsing
6.加载插件
7.是否使用pidfile(pidfile主要是用来控制保证只有一个deamon进程运行的)
注解:
pidfile一般用于daemon程序,主要作用是保证在系统中只存在该daemon的一个进程,同时也便于系统统一管理这些daemon程序。
start过程需要处理的问题:
· 1.1 确保系统中没有该daemon的进程。如果有,则不能启动程序。
· 1.2 在daemon化之后,创建pidfile,写入pid。
· 1.3 注册atexit(),确保在程序退出时清除pidfile文件。
stop过程做的处理:
· 2.1 如果pidfile不存在,无需其它动作。
· 2.2 如果pidfile存在,kill原有进程,并确认进程不存在。在旧进程异常退出时,比如直接用_exit(2)退出程序时,可能pidfile不会被删除,所以在kill进程之后还要确认pidfile文件已被删除。
restart动作:
· 3.1 stop
· 3.2 start
8.如果使用select模型,设置最大fd数
9.各种最大资源数的设置,因为涉及很多结构体,不详述
10.网络部分初始化 network_init
11.插件调用的初始化
12.进程守护化
13.写入pidfile
14打开log文件,之前都是设置写入STDERR。因为转化为daemon了,没有终端关联,必须有输出文件
15配置插件
16丢弃没有使用的配置项
17信号处理函数绑定
18产生子进程(工作进程)
由监控进程产生工作进程并wait
(这里将SIGHUP解释为Reset,Recongfig,重新读取配置文件而不重启。
forwarded_sig_hup在kill后变为1,保证kill只调用一次
如果受到信号导致SIGTERM或者SIGINT信号
case SIGTERM: srv_shutdown = 1; break;
case SIGINT:
if (graceful_shutdown) srv_shutdown = 1;
else graceful_shutdown = 1;
监控进程跳出循环,结束所有子进程,然后回收资源)
这里拷一副图,来自《lighttpd源码分析》
工作进程流程:
1.多路复用初始化 fdevent_init
2.事件注册network_register_fdevents
3.stat_cache_init //缓存初始化
4.关于FAM的设定// 需要有usr/include/fam.h 在中声明了 base.h:# include
注解:
FAM(文件变更监视模块)
FAM就是文件变更监视模块,它向应用程序提供了一组API,当指定的文件或目录发生变化时,由其向应用程序发出通知。
FAM由两部分组成:后台守护程序fam,它负责接收请求和发送通知;库文件libfam,客户端应用程序用它来与FAM通信。
若远程主机打开了受监视的文件,本地的fam会与远程主机的fam联系,将请求发送给远程fam。
Fam也可以在某个文件开始或停止运行时通知它的客户端。(比如:在IRIX交互桌面中,如果一个程序正在运行那么它的图标就会不会闪烁)。
5.Socket赋值(前面多路复用模块已经初始化了)
6.大循环
{
if(接到SIGHUP信号)
{
调用插件处理HUP信号的函数plugins_call_handle_sighup(srv)
重新打开log日志文件,并写入收到HUP信号的记录。
l og_error_cycle
}
if(收到时钟信号)
{
重置handle_sig_alarm
比较当前时间和服务器上次记录时间,如果不相等则进行下面处理:
plugins_call_handle_trigger;
设置服务器记录时间为当前时间;
stat_cache_trigger_cleanup(srv);
处理超时连接
(这里好多结构体对应的函数没见过,先跳过。大体流程就这样)…..
}
根据上面的大体流程,有下面的子模块需要阅读和研究(不够的话补充):
server结构体
配置文件结构体
安全性研究
日志系统
复用技术模型
插件链、基本插件模块
网络请求服务相应和流程network部分
文件状态缓存器 stat_cache
其他常用结构体
下面是我阅读这部分代码总结的知识点:
知识点一:SIGINT和SIGTERM的区别(这部分是转载的)
首在这三个信号中,sigkill是不能被捕获的,程序收到这个信号后,一定会退出。这就是kill -9一定能保证将程序杀死的原因。
信号 |
产生方式 |
对进程的影响 |
sigint |
通过ctrl+c将会对当进程发送此信号 |
信号被当前进程树接收到,也就是说,不仅当前进程会收到信号,它的子进程也会收到 |
sigterm |
kill命令不加参数就是发送这个信号 |
只有当前进程收到信号,子进程不会收到。如果当前进程被kill了,那么它的子进程的父进程将会是init,也就是pid为1的进程 |
信号收到不一定立即处理,如果在内核态会存在安全隐患
知识点二:sig_atomic_t使得变量的操作具有原子性,比如服务器状态设定,不被其他中断打断
volatile是一个类型(type specifier)。它是被设计用来修饰被不同线程访问和修改的。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么失去大量优化的机会。
知识点三:进程的权限问题:涉及到安全性 http://blog.chinaunix.net/uid-27105712-id-3349522.html
知识点四:
sigaction函数的使用
该函数根据参数signum指定的信号编号来设置该信号的处理函数
知识点五:
定时器的使用
http://www.cnblogs.com/wanghetao/archive/2011/12/01/2270628.html