项目笔记 | 基于自建http协议的共享目录服务器
前言
百度网盘存储功能方便了我们存储资料不仅限于物理设备,但是对于普通用户难以忍受限速的操作。在学习了网络编程之后,决定自己写一个基于http协议的共享目录,方便客户端将文件目录上传到服务端,支持目录列表展示,文件上传,文件下载,断点续传。
1. 框架流程
跟着想法画的,难免有些粗糙:
对流程总结一下:
- 搭建tcp服务器,用epoll进行事件监控
- 判断事件是监听事件时,放置线程池任务队列,调用任务处理函数
- 任务处理函数,分为,http请求解析,随后对组织http响应返回给web端
- 对http请求的方法和参数,路径进行判断
1.如果时GET方法,且有参数,或者POST请求,执行CGI
2.如果为GET方法,查询路径不为空 即为 列表展示否则就是文件下载
3. 请求解析
- 先接受整个头部信息,判断有没有空行,如果有则表示整个头部信息接受完整
- 通过找到换行符\r\n,划分首行和头部。
- 在头部里找到Content-Length字段,即可知道正文长度,后续方便接受正文。
3.1 首行解析
- 首先找到空格出现的地方,前面就是请求方法和http协议版本
- 空格后面是url和请求参数,通过找到?划分这两个
- 请求参数以& 分割,所以每次找到它,以key-value方式存储
3.2 头部解析
- 头部的信息以: 分割,所以找到每次找到它,就存储前后的信息,也是以map形式存储。
4. 文件上传
这里用到了CGI,如果不用CGI,而是服务器直接处理表单数据,那么大量并发情况下,服务器很容易挂掉
- 在父进程了fork子进程,建立匿名管道实现父子进程通信
- 由于父进程只需要写,所以关闭读端,子进程只需要读,所以关闭写端
- 此外,由于父子进程互相独立,在进程替换后,子进程会失去父进程的文件描述符
- 所以将父进程的管道重定向到标准输出,子进程重定向到标准输入。
- 将头部信息以环境参数传到子进程
- 程序替换后,执行子进程,子进程拿到找到Content-Length,接受正文
- 解析表单数据,其实就是解析boudnary,一共三段,数据存放在中间。
- 判断文件是否正确,并向父进程返回响应信息。
5. 文件下载
- 在头部信息找Range字段,如果没有就是普通文件下载,如果有就是断点续传
- 拿到Byte字段,找到Range的开始值和结束值。
- 下载这个范围的数据
- 组织头部响应,状态码必须是206,还有Content-Range字段,后面跟着刚才Range的范围;
还有Etag信息,Content-Type信息设置为“application/octet-stream”
6. 列表展示
通过boost库的文件迭代器, 将查询路径的每一个文件,通过boost的文件修改时间,文件大小获取,随后写进输出流中,写进正文里,组织响应给客户端。