zorrock +

小型的 HTTP 服务器thttpd

官方网址:thttpd

下载 version 2.25b 的源码后解压,切换到源码目录,编译步骤为:

./configure
make

thttpd一共有16个源文件:

config.h fdwatch.h libhttpd.h match.h 
mmc.h tdate_parse.h timers.h version.h
fdwatch.c libhttpd.c match.c mmc.c 
strerror.c tdate_parse.c thttpd.c timers.c 

首先梳理编写守护进程(daemon)遵循的一般步骤:

下面是主模块的大体流程图:

main()
{
	打开系统日志
	处理main参数
	读取流控配置文件
	设置UID
	获取当前工作目录
	切换到后台模式
	创建子进程,父进程结束
	获取系统资源信息
	注册处理系统信号的函数
	初始化定时器资源
	初始化http server对象
	创建系统定时器
	创建连接表定时器
	创建连接表数组
	将监听套接字加入select集合
	主循环
	{
		获取套接字集合发生的事件
		检查套接字上的发生的具体行为
		接收新的连接
		处理新的连接
	}
	销毁http server对象
	关闭系统日志
	退出
}	

##mmc模块分析 映射文件到内存,如果定义了HAVE_MMAP,使用mmap,否则使用malloc。

mmc_map函数的步骤是:

mmc_unmap函数的步骤:

mmc_cleanup函数的步骤: 遍历全局变量maps,当此Map上的引用计数为0或者时间过期了,调用really_unmap。如果空闲总数大于DESIRED_FREE_COUNT,循环删除全局变量free_maps链表的头部的元素,直到free_count<=DESIRED_FREE_COUNT。

really_unmap函数的步骤: munmap取消内存映射,将这个Map结构添加到free_maps链表的头部,减少映射总数,增加空闲总数。

mmc_destroy函数的步骤: 遍历maps链表,调用really_unmap,然后遍历free_maps链表,释放内存,减少空闲总数、分配总数。

check_hash_size函数的步骤: 当hash_table为空时,初始化hash_size、hash_mask,当hash_size >= 3倍的映射总数,直接返回,否则释放掉原先的哈希表,增大hash_size,malloc(hash_size)大小的内存,遍历maps链表,调用add_hash将所有元素添加到哈希表中。

##fdwatch模块分析

此源文件根据Makefile中的宏定义决定采用哪种模型。

select,kqueue -- BSD系统
poll  -- SysV系统

fdwatch_get_nfiles函数的功能: 获取可操作的文件描述符总数; 根据HAVE_SELECT,HAVE_POLL,HAVE_DEVPOLL,HAVE_KQUEUE这其中的哪个宏被定义,调用宏INIT,因为HAVE_SELECT宏被定义,所以INIT被定义为select_init。

fdwatch_add_fd 宏ADD_FD被定义为select_add_fd

fdwatch_del_fd 宏DEL_FD被定义为select_del_fd

fdwatch 宏WATCH被定义为select_watch

fdwatch_check_fd 宏CHECK_FD被定义为select_check_fd

fdwatch_get_next_client_data 宏GET_FD被定义为select_get_fd

##libhttpd模块分析

httpd_initialize函数的功能: malloc(httpd_server),申请一块内存用来保存httpd_server这个结构体,然后设置这个结构体中的成员; 根据参数sa6P和sa4P创建套接字,绑定套接字,然后监听这个套接字; 初始化mime媒体类型。

httpd_unlisten函数的功能: 调用close关闭监听套接字

httpd_get_conn函数的功能: httpd_realloc_str分配内存空间; 调用accept接收客户机的连接,对httpd_conn结构体中的字段进行赋值

httpd_parse_request函数的功能: 调用bufgets获取远程连接的HTTP各个字段,如HTTP版本,mime类型。

httpd_close_conn函数的功能: 释放文件映射,关闭此套接字连接

ls函数的功能: 扫描指定目录下的子目录和文件,列出文件名,属性,链接数,大小,修改时间。

##thttpd主模块分析

handle_term函数的步骤是: 对信号SIGTERM,SIGINT进行处理的函数

parse_args函数的步骤是: 处理进程启动时传递的参数,设置相应的全局变量。

read_config函数的步骤是: 读取配置文件,设置相应的全局变量。

read_throttlefile函数的步骤是: 读取‘流量控制配置文件’,设置throttletab。

shut_down函数的步骤是:

handle_newconnect函数的步骤是:

handle_read函数的步骤是:

finish_connection函数的步骤是:

really_clear_connection函数的步骤是:

idle函数的步骤是:

show_stats函数的步骤是: 调用logstats函数,logstats函数调用thttpd_logstats、httpd_logstats、mmc_logstats、fdwatch_logstats、tmr_logstats记录日志。

main函数的步骤是:

此外,有两个文本文件mime_encoding.txt mime_types.txt,在makefile.in里做处理,用sed格式化,生成mime_types.h,mime_encodings.h,在libhttpd.c中用#include引进来。

点击查看评论

Blog

Opinion

Project