http服务器究竟做了什么(四)

这篇开始讲服务器的代码.为了让初学者更好的理解http服务器的基本原理,抓住主干,排除其他干扰,我这里用了最轻量级的http服务器tinyhttp,总共代码只有500行左右.麻雀虽小,五脏俱全. tinyhttp实现了http服务器的基本功能.

首先,初学者要懂基本的socket编程,知道socket编程的基本流程.因为http服务器也是基于socket编程的.

为了更直白的演示http服务器的流程,tinyhttp没有采用复杂的网络模型,而是采用最基本的多线程来处理新的连接.即没有一个新的socke连接都开启一个新的线程.

当收到浏览器请求之后,解析请求头,根据是否为get,post进行相应的处理.http协议头都是文本协议,而且每个字段都以\r\n来分隔,所以我们可以封装一个函数get_line,专门解析一行的数据.

有个问题就是,由于各个系统的分隔符不一致,比例windows是\r\n,linux为\n,mac又是\r,所以这里要特别的处理一下,以适应各种不同的系统.这里有个处理技巧,当遇到\r的时候,怎么知道是一行的结束了,还是后面会有\n?可以用MSG_PEEK参数,窥看一眼后面的数据,如果后面的一个字符不是是\n,说明这一行已经结束,否则就要再读\n来结束这一行.

有了上面的get_line函数,我们解析出浏览器请求的方式.我画了get_line的大致流程图,如下:


可以看到,如果只是单纯的请求文件,那么只需要server_file,读取并发送文件内容即可.如果是POST或者带参数的GET,则要执行CGI程序.这里我们重点讲一下服务器是如何与CGI程序交互的.

我们知道,CGI程序实际上也是一个用户进程.服务器以子进程的方式来启动他,这样他们就可以共享环境变量,进程间的通信也变的简单很多.

基本的环境变量有区分GET或POST的REQUEST_METHOD,对于GET,肯定有QUERY_STRING,而POST必定会有CONTENT_LENGTH,由于以子进程的方式打开,这些环境变量都会进入到CGI程序的环境变量中.

对于GET方式,没什么好说的,CGI程序获取环境变量的值就行,而对于POST方式要复杂一点.环境变量中只有CONTENT_LENGTH,获取到他的值之后,还要读取socket,才能获取POST真正的数据.

问题来了,服务器读取CONTENT_LENGTH长度的数据之后,怎么把这个数据传给CGI程序?然后CGI程序又是怎么把处理结果返回给服务器的呢,不管是GET还是POST肯定都需要传回数据的,否则浏览器展现什么呢.

这里不能再次利用环境变量了,因为环境变量只适合共享那些比较小的数据,像网页页面数据那么大肯定是不适合这种方式的.父进程和子进程还有另外一种易操作的通信方式--匿名管道.可以参考匿名管道为什么可以在父子进程间通信.

我们建立两个管道input,output.服务器获取POST体的数据之后写入input管道的一端(input[1]),CGI程序就可以从input的另一端input[0]获取POST体数据了.奇怪的是CGI程序是如何获取管道的另一端的呢?这里利用了一个很巧妙的方式--重定向,利用dup2将input[0]重定向为CGI程序的输入文件描述符.

CGI程序执行业务逻辑之后,给服务器返回数据则通过output管道.同理将管道的一边output[1]重定向为CGI程序的输出文件描述符.只要CGI程序向标准输出写入,那么管道的另一边,服务器的output[0]就能收到数据,进而发送给浏览器.












  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值