所谓的HTTP,本质就是把服务器上的文件资源想方设法的发送回给浏览器。
web服务器要做的两件事:
1、从http请求中提取出要访问什么资源
2、找到资源且判定资源是否合法,合法情况下打开,打开之后读取,读取之后发送回去,发送完关闭。
要面对的问题:
1、HTTP协议本身的解析问题
2、HTTP资源的返回问题
基本框架
httpserver.hpp | 服务器、端口相关设置 |
sock.hpp | 对套接字的封装,满足基本通信要求 |
Protocol.hpp | 专门处理协议细节,Request(对读上来的请求做分析)、Response(构建响应)、Endpoint(桥接请求与响应) |
util.hpp | 与逻辑业务无关,单纯完成某些功能 |
log.hpp | 日志信息,用打印的方式充当日志 |
threadpool.hpp | 让线程去完成请求与响应 |
main.cc | 主要调用逻辑 |
makefile | |
wwwroot | web根目录,把所有文件放在该目录 |
cgi | 运行cgi部分的代码 |
ctrl.sh | 服务器控制脚本,用于实现服务器的启动,暂停,重启和状态查看 |
任何一个web服务器的部署上都要有一个index.html (在wwwroot内 )
日志信息包含:
[日志级别]:notice,warning,error,fatal(致命),不同的级别处理方式不同。
[message]:信息提示
[时间戳]
[filename] :文件名
[line]:行号
需求分析
1、能够处理GET、POST方法请求的资源
2、服务器将请求的资源以html页面的形式呈现,并能够进行错误处理(比如:当请求的资源不存在时,服务器能够返回一个404的页面)
3、可以进行简单的cgi运行。(比如在表单中输入数据后,服务器能够将运行结果返回个客户)
主要的处理逻辑
1、当服务器收到请求后,首先分析请求方法是POST还是GET(此项目只处理这两种方法)。
2、GET和POST的参数位置不同,GET的参数在URL中,POST的参数在请求正文中所以第二步要拿到请求的URL,为我们之后能处理GET和POST方法的cgi。
3、判断资源是否存在,如果存在,判断这个资源是一个目录、普通文件还是一个可执行程序。
GET方法:
- 如果没有参数,就直接将请求的资源返回(即进入非cgi模式运行);
- 如果有参数,进入cgi模式内部运行。
POST方法:有无参数都直接进入cgi函数内部运行。
非cgi模式:
进入非cgi模式时一定是GET方法且没有参数,此时进入echo_www()函数内部即可,该函数会将所请求的资源以html的格式返回给浏览器。
HTTP CGI:
上述这张图描述了运行cgi时的过程,首先服务器要从浏览器上读取参数,然后需要fork出一个子进程进行cgi部分的处理,父进程通过环境变量的方式将参数转交给子进程,子进程运行完后,将结果交给父进程,父进程再将数据输出给浏览器。在这个过程中可以将父进程看作一个中间量,只进行了参数的转交,因此可以将子进程的输入输出文件描述符进行重定向,即子进程直接与浏览器“联系”。
父子进程内部需要做的事情:
父进程:
- 创建两个管道,并关闭相应的文件描述符
- POST方法:继续读取数据,直到读完POST的参数部分
GET方法:直接从子进程读取结果 - 将数据和方法全部交给子进程后等待子进程的结果
子进程:
- 关闭管道适当的文件描述符
- 对标准输入输出进行重定向
- 通过环境变量传递参数
- 进行exec程序替换
项目扩展
1、内存池项目+http
2、技术方向:处理更多的方法(如hand),状态码多样化,长连接(一条连接处理多种请求)
3、业务方向
总结:
自主开发小型的web服务器,可以进行基本的网页请求,静态网页返回和交互式网页的信息的返回。主要是用http协议结合套接字、多线程技术和部分系统变成完成的一款网络服务器。
项目源码:https://github.com/LumosN/webServer