项目介绍
这个项目是一个基于线程池IO模型实现的网络通信http服务器。
项目框架
项目大致由4个部分组成。
1、tcp服务器,用于建立TCP连接。
2、http服务器,建立监听套接字,将接收到的新的套接字push到线程池中的任务队列中,
3、线程池中的线程循环处理任务队列中的任务,调用回调方法,也就是执行IO通信。
4、IO通信就是任务执行回调的方法。在这里完成http报文的接收、解析和构建响应报文,并发送响应报文的工作。
读取的过程按行读取,直到遇到空行,请求行和请求报头就读完了。空行的后边便是正文部分。
解析请求行的过程是按空格提取字段信息的。
解析请求报头是按空格加冒号的格式提取头部字段信息。
技术点
线程池
线程池中维护着一个任务队列和若干线程,需要互斥锁和条件变量结合使用。条件变量维护任务队列的同步,互斥锁则维护线程的同步。即一种生产者消费者模型的线程池。
cgi
cgi是将http接收到的参数,传递给cgi程序执行,再将执行结果返还给http发送给客户端。
http是如何将参数传递给cgi程序,cgi程序又是如何将结果返还给http的呢?
首先,我们得直到http传参的方式分为get和post传参,get通过url传参,post则通过http正文传参。
get通过url传参,因为url毕竟有长度,因此可以通过环境变量传递。而post通过http正文传参,其长度无法预测,采用匿名管道的方式传参。
http接收到参数,然后交给cgi程序执行,这个过程可以看作是两个进程的执行过程,可以采用程序替换,使用execl系列函数实现。
程序替换之后,使用匿名管道的文件句柄等数据也被替换了。但是我们深知默认的标准输出、标准输入和标准错误的文件句柄是0、1、2。因此在执行execl之间,对使用匿名管道的文件句柄进行重定向,这便完成了http和cgi之间的通信。
ps(cgi接收post传递的参数时,http需要先将请求头部中的Content-Length字段通过环境变量的方式告知cgi,这样cgi才能准确接收post正文部分的参数)。
项目反思
这里思考的主要时cgi部分http与cgi程序通信的过程。
execl系列函数执行,环境变量不会被替换吗?因为环境变量具有全局属性,不会被替换掉。
为什么会选择匿名管道进行通信?原因如下:
1、匿名管道只允许亲缘关系进程单向通信(符合)
2、匿名管道内部保证了同步机制,从而保证数据访问的一致性。且面向字节流(安全性)
为什么不考虑其他的通信方式?
命名管道?命名管道是通过文件名+路径的方式让不同进程看见同一分资源的,也就是说该资源存在磁盘上,如若操作不当,便会出错。
共享变量?通过将共享的内存缓冲区直接附加到进程的虚拟地址空间中来实现的.因此,这些进程之间的读写操作的同步问题操作系统无法实现。必须由各进程利用其他同步工具解决。共享变量大多和信号量搭配使用。
套接字?类似杀鸡用牛刀的感觉。
综上匿名管道的特点是最符合http和cgi程序之间通信的方式。