tinyhttpd源码分析
2016-01-21 13:39
776 查看
我们经常使用网页,作为开发人员我们也部署过httpd服务器,比如开源的apache,也开发过httpd后台服务,比如fastcgi程序,不过对于httpd服务器内部的运行机制,却不是非常了解,前几天看见tinyhttpd,只有短短500行左右的代码,就实现了一个简单的httpd服务器的基本功能,这种tiny程序,其实对于我们了解基本核心有一定的帮助,可以通过分析其代码,了解构建一个简单的httpd服务器需要的基本元素。
(1) startup函数
这个函数的代码非常简单,其实就是简单创建一个server端的socket,让它绑定指定的端口,然后开始listen
(2) accept_request函数
此函数中首先解析客户端的请求方式,是GET,还是POST,tinyhttpd只能处理这2种请求,如果都不是,就返回错误。然后解析请求的url,然后对应到服务器中tinyhttpd中htdocs目录下的文件,检查文件状态,如果文件不存在,那么返回错误。如果文件存在,是GET方法时,tinyhttpd直接返回此文件,通常是html。如果是POST,那么会执行对应的.cgi文件,tinyhttpd中的CGI文件,是用PERL脚本实现的。
(3) execute_cgi函数
此函数中就是如何执行CGI脚本的地方,首先还是将POST部分的数据解析出来,然后fork一个子进程去执行CGI脚本,这里有一个小的技巧,就是tinyhttpd使用了管道来让执行CGI脚本的子进程,通过标准输出写入和父进程的管道中,父进程在fork之后,读取此管道中的数据,然后返回给客户端。
父进程中创建管道的代码:
这里创建了2个管道,每个管道都有一个写端,一个读端。
子进程是通过下面代码执行的:
父进程中,读取管道中的内容:
color.cgi代码:
单独在控制台下运行的结果是:
也就是说,tinyhttpd通过子进程运行PERL的CGI脚本,然后脚本输出了一个HTML,这个HTML内容通过父子进程之间的管道进程消息传递,父进程读取管道中的内容发送给浏览器。
不过我们从代码中只看到了设置环境变量putenv的部分,如果是POST方法,并没有看见设置参数的部分,其实这部分代码,是在fork之后,parent中通过for循环,将content_length长的content通过管道write给了子进程的标准输入,这也就是为什么在fork子进程之前先创建了2个管道的原因。
这样,整个tinyhttpd核心的内容就结束了。
(1) startup函数
这个函数的代码非常简单,其实就是简单创建一个server端的socket,让它绑定指定的端口,然后开始listen
(2) accept_request函数
此函数中首先解析客户端的请求方式,是GET,还是POST,tinyhttpd只能处理这2种请求,如果都不是,就返回错误。然后解析请求的url,然后对应到服务器中tinyhttpd中htdocs目录下的文件,检查文件状态,如果文件不存在,那么返回错误。如果文件存在,是GET方法时,tinyhttpd直接返回此文件,通常是html。如果是POST,那么会执行对应的.cgi文件,tinyhttpd中的CGI文件,是用PERL脚本实现的。
(3) execute_cgi函数
此函数中就是如何执行CGI脚本的地方,首先还是将POST部分的数据解析出来,然后fork一个子进程去执行CGI脚本,这里有一个小的技巧,就是tinyhttpd使用了管道来让执行CGI脚本的子进程,通过标准输出写入和父进程的管道中,父进程在fork之后,读取此管道中的数据,然后返回给客户端。
父进程中创建管道的代码:
if (pipe(cgi_output) < 0) { cannot_execute(client); return; } if (pipe(cgi_input) < 0) { cannot_execute(client); return; }
这里创建了2个管道,每个管道都有一个写端,一个读端。
子进程是通过下面代码执行的:
execl(path, path, NULL);
父进程中,读取管道中的内容:
while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0);
color.cgi代码:
#!/usr/bin/perl -Tw use strict; use CGI; my($cgi) = new CGI; print $cgi->header; my($color) = "blue"; $color = $cgi->param('color') if defined $cgi->param('color'); print $cgi->start_html(-title => uc($color), -BGCOLOR => $color); print $cgi->h1("This is $color"); print $cgi->end_html;
单独在控制台下运行的结果是:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US"> <head> <title>BLUE</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> </head> <body bgcolor="blue"> <h1>This is blue</h1> </body> </html>
也就是说,tinyhttpd通过子进程运行PERL的CGI脚本,然后脚本输出了一个HTML,这个HTML内容通过父子进程之间的管道进程消息传递,父进程读取管道中的内容发送给浏览器。
不过我们从代码中只看到了设置环境变量putenv的部分,如果是POST方法,并没有看见设置参数的部分,其实这部分代码,是在fork之后,parent中通过for循环,将content_length长的content通过管道write给了子进程的标准输入,这也就是为什么在fork子进程之前先创建了2个管道的原因。
这样,整个tinyhttpd核心的内容就结束了。
相关文章推荐
- The type javax.servlet.http.HttpServletRequest cannot be resolved.
- 5. http://kb.cnblogs.com/page/90838/
- 新浪实时股票数据接口http://hq.sinajs.cn/list=code
- 神经网络(Neural Network)
- 网络加密解密原理(一)
- 升级到iOS9.0后,Http请求导致应用加载不出数据
- 网络
- BZOJ 1491: [NOI2007]社交网络( floyd )
- Java网络编程--简易下载器实现
- Http StatuCode说明
- Android自定义圆角ImageView 支持网络图片
- ※回顾※关于阅读TCPIP等源码时遇到的:do while(0) 用法
- Nginx HTTP请求流程
- CNN Note
- httpclient 4.3及以上版本,发送和接收https
- https双向认证(基于程序访问,j2ee和android上皆可用)
- Android ImageCache图片缓存,使用简单,支持预取,支持多种缓存算法,支持不同网络类型,扩展性强
- HttpClientHandler
- 解决UDP丢包问题的经验
- iOS TCP三次握手过程 有意思的解释