Mongoose是一种WEB服务器,因为最近在学习网络编程,所以打算研究研究它的源码,认真看了大部分,觉得学到的东西的确不少,拿出来分享一下,也和大家交流交流
至于什么是WEB服务器,以及Mongoose作为一种轻量级的WEB服务器,它有哪些优点,这里给个链接:http://www.cnblogs.com/skynet/archive/2010/07/24/1784322.html
刚开始,也是看作者的文章才产生兴趣读源码,所以分享很重要(^o^)
如果想快速的阅读源码,可以先预览一下UserManual.md这个文件,用户手册告诉我们怎么去使用这个服务器,以及如何使用它提供的功能。
好的,编译运行请看那位吴哥的文章,这里,我直接把我读源码的笔记整理出来:首先我们看程序的主体框架,细节决定成败,但是从整理上入手,我们能走的更远。
程序的框架:
Mongoose采用的是线程池模型,有两个关键的数据结构,mg_callbacks和mg_context,前者是一系列函数指针集合,在程序的执行过程中我们会调用这些函数,后者则是Mongoose的核心,数据结构后面单独分析,回到程序框架上来
- main(){
- //处理用户的输入
- process_command_line_arguments();
- //设置中断信号
- signal(SIGTERM, signal_handler);
- signal(SIGINT, signal_handler);
- //开始
- mg_start();
- while(exit_flag == 0)
- sleep(1);
- //结束
- mg_stop();
- }
程序的开始:
程序开始于mg_start,结束于mg_stop,在mg_start()中,分别生成主线程和工作线程,工作线程我们可以自己配置,默认是50个
mg_start_thread(master_thread,ctx)
mg_start_thread(worker_thread,ctx)
然后分为两条线路:
1. Master_thread()中采用poll来处理监听套接字,对于每一个监听套接字,当有新的连接请求时,调用accept_new_connection()处理新的连接。accept_new_connection()中调用produce_socket()产生新的连接套接字,产生的连接套接字放入线程池队列中,因为是多线程,所以要考虑线程同步问题,这里采用了“生产者---消费者”模型,很好的处理了同步问题
2. worker_thread()中作为消费者,我们调用consume_socket(),然后调用process_new_connection()来处理新的连接,实质是调用handle_request()函数,至此整个程序的框架一目了然
程序的结束:
我们在main函数中sleep了,当我们收到了信号例如键盘上的ctrl+c,
static voidWINCDECL signal_handler(int sig_num) {
exit_flag = sig_num;
}
中修改了exit_flag,然后程序进入mg_stop(),
- void mg_stop(struct mg_context *ctx) {
- ctx->stop_flag = 1;
- while (ctx->stop_flag != 2) {
- (void) mg_sleep(10);
- }
- }
修改了mg->stop_flag = 1,然后等待其变为2, 其实就是去清理线程数据,我们在master_thread()中看到最后一句ctx->stop_flag = 2,至此,程序就退出了,以上就是程序的结束流程。
程序的框架图大体是这样的: