整体思路: 创建socket监听请求,收到请求后线程分离,在线程中进行请求数据的解析;根据解析到的消息我们分类处理,目前该文件服务器可提供的文件包括html、css、jpg、gif;
1.监听请求,; 首先设置了端口复用,这个从字面理解就好了,就是说该端口上可以绑定多个socket;分配套接字,Http文件服务器是基于TCP传输协议; 初始化监听的地址结构体; 套接字与地址结构体绑定;
![4cced834e26b30e37dc8c4d020d10823.png](https://i-blog.csdnimg.cn/blog_migrate/05eff7246b2bb92af405df89276d32a6.jpeg)
2.循环监听,这里的accept函数是从步骤1中的listen函数的等待请求队列里接受一个连接; 自定义结构体,打包了文件描述符,地址,地址大小; 创建线程并分离,所有的处理工作在do_work函数中;
![738cfa5057353b328b67d867c036806e.png](https://i-blog.csdnimg.cn/blog_migrate/88cd40ea841d64ad75ea9ed5ba50bbcd.jpeg)
3.do_work()函数
3.1 初始化
![cfc5c16aaf7aa40d5e22c1ff63e8be85.png](https://i-blog.csdnimg.cn/blog_migrate/2ae360efd0aab8af15346e174bfde893.jpeg)
3.2 进入函数后不要盲目的直接调用开始处理请求行,我们先判断这个客户端的下一步动作,
如果recv返回了但是num为0,说明客户端套接字主动断开连接,这里直接goto到线程
收尾工作;
![237938a083a08d3f6978f97876697fa8.png](https://i-blog.csdnimg.cn/blog_migrate/5f5142e8bc7864d6f0a9a5f731f002d9.jpeg)
3.3 处理请求头的第一行数据,一般格式是 (方法 文件路径 协议版本)
例如:GET /index.html HTTP/1.1
注意: #define ISsp(x) isspace((int)(x)) //用于判断空格;
get_line()函数 获取一行数据,自定义函数,以 rn判断;
![8b6e704fa7939e96b7230164ca8a9dc6.png](https://i-blog.csdnimg.cn/blog_migrate/3602d9d31055f6b4118604d85459380e.jpeg)
3.4 获取URL,即获取客户端想要请求的文件路径;
![f8a7eeb567ea4e06333b4923b55455c5.png](https://i-blog.csdnimg.cn/blog_migrate/6d0bb2d42fdcd4f8835afaa1a7e0f76d.jpeg)
3.5 客户端请求的URL一般是请求的Http文件服务器的站点目录
如果请求的是 /index.html ===> 那么在我的设置里对应的 是/root/Project/WebFileServer/File/index.html
一定要区分客户端请求的根目录其实是服务器上的站点根目录
![1f610eee571305ee4144aad8e88499de.png](https://i-blog.csdnimg.cn/blog_migrate/790ca9f37bfec13a00c0ebad34bb0fa5.jpeg)
3.6 返回文件根据cgi的值,cgi等于1代表是POST,我们提交到cgi程序处理; cgi等于0代表是普通的GET,文件服务器直接返回静态文件;
![ced69f58880afb927072418fa9ae2669.png](https://i-blog.csdnimg.cn/blog_migrate/b6a8144b3fc59a49761822255320ade0.jpeg)
4.get_line()函数 : 该函数为Tinyhttpd源码,可以放心的使用
![cbf4a55a34bceb19024cbc3405ee400d.png](https://i-blog.csdnimg.cn/blog_migrate/9c69c2436e3fd27fe21313ad64a067fd.jpeg)
5.提供静态文件(其中包括html、css、jpg、gif、下载文件)
![2eb1925f6dcb7737060eb8e30c2ea1b3.png](https://i-blog.csdnimg.cn/blog_migrate/c605d3d2f4c7c99116c7c23e07bc8316.jpeg)
6.这里给出只给出提供html文件的函数和下载文件函数;其他函数实现类似
![256802b043398785a6caf4abe85203e0.png](https://i-blog.csdnimg.cn/blog_migrate/3697e231e1b1add86f8c34a98e61ec1f.jpeg)
下载文件需要注意的是返回类型,在html返回中服务器的发送的响应头里,Content-Type设置的是text/html;在下载类型中需要采用application/octet-stream,此为下载类型,用二进制传输文件;
注意:该下载文件实现是用的大文件分块传输,切记发送数据时要保证文件要关闭,不要在打开文件的状态传输数据,当客户端关闭时服务器会退出;
![4ab237a5f351f54cb73522bc74b67efe.png](https://i-blog.csdnimg.cn/blog_migrate/267d7a3a1014230cf84a5e0cb13303d6.jpeg)
![e5b373535cd79b12fb1e4a195f31467f.png](https://i-blog.csdnimg.cn/blog_migrate/7527f37ea65d12132061647769322124.jpeg)
![fe5de4bced471c80fac37dda3a744691.png](https://i-blog.csdnimg.cn/blog_migrate/a8edf24dd3c1a3a684b9ba9b406bdd4c.jpeg)
7.文件上传
首先是客户端,一般采用POST方法提交到文件服务器上的一个cgi程序,在步骤3.6中我们实现了提供静态文件,这里来描述如果利用cgi上传文件到服务器;
步骤为:客户端按下按键发送一个带有文件的POST请求 ==> 服务器接收请求并获取文件信息 ==> 服务器接收文件数据并存储
客户端的提交信息:
POST /CGI/down.cgi?filename=xxx HTTP/1.1rn
… …rnrn
(file data)
这里请求了根目录下CGI目录中的down.cgi这个程序,提交的文件名放在xxx这个位置,这部分是在客户端实现的;服务器收到请求调用down.cgi ; 该cgi可以用C写也可以用Shell,Python… … 本次采用的C语言实现cgi程序;
![3373b16feaa3f764f67831f4ad7f54da.png](https://i-blog.csdnimg.cn/blog_migrate/12eaed3121ac510856e36edd77c72e8b.jpeg)
![8b758546df4d86456241be9dc6b0650a.png](https://i-blog.csdnimg.cn/blog_migrate/21f2d67f107e9cfb6076d0b2eb08fd07.jpeg)
感谢你耐心的看完了这篇文章,希望能够帮助到你。