C语言手写HTTPD网站服务器

网站服务器(HTTPD)已经有很多版本,但是大部分对初学者都非常不友好。适合初学者学习的httpd服务器,最负盛名的当数tinyhttpd, 但是这个版本,是基于Linux系统的,而且配套的CGI也是使用perl语言写的,直接劝退了大部分想学后端开发的初学者。基于此,特意写了这个小项目,让只有C语言基础的初学者,就可以直接手写后端服务器,快速提升C语言和网络开发技能。
这个项目是基于tinyhttpd改写的,解决了以下问题:
1. 解决了tinyhttpd服务器只支持html纯文本的问题,添加了支持图片文件和JS脚本的问题,可以直接支持各种复杂的网页。
2. 使用C语言实现了CGI功能。tinyhttpd服务器的CGI是perl脚本实现的,对于C/C++初学者不友好,用C语言实现CGI功能,可以更加深刻的理解动态网站的实现原理和实现方法。
3. 解决和tineyhttpd服务器中文显示的问题,完美支持GET和POST的中文字符。
4. 本项目直接使用Window系统实现,C/C++初学者可以零障碍掌握学习。tinyhttpd服务器是基于Linux系统的,而大部分初学者对Linux系统并不熟悉。
5. 本项目在最后使用内网穿透,把自己的网站零成本的分享给自己的同学朋友。
项目效果点这里看本教程配套视频
项目准备
Windows系统
vs2019或者任意其它版本的vs
创建项目
创建项目
使用任意版本的VS或者VC++,创建一个空项目。

创建服务器端的套接字
基于网络的通信,需要先创建“套接字”。“套接字”这个专业术语,非常古怪,被很多人吐槽。我们不要深究它为什么叫这个名字,我们只需要了解“套接字”的作用即可。
套接字,就相当于一个“网络插座”,通过网络进行通信,就是通过这个“插座”收发信息的,相当于一个电话机的电话线插槽。

在创建服务器时,还必须要指定一个端口号。当一台服务器,同时对外提供多种服务时,比如WEB服务,远程登录服务等等,就需要使用“端口号”,对不同的服务进行区别。每个服务,都有自己唯一的端口号。

但是,服务器端在网站访问服务之前,需要创建“套接字”。

以上代码,只是写了函数接口,还没有真正创建套接字。马上做详细的实现。
执行WEB服务前的准备工作
在接受浏览器前端的网页请求之前,服务器端需要做一些准备工作,流程如下:(详细详解可以参考本教程配套的分享视频)

代码实现如下:



接收浏览器的WEB请求
我们的httpd web服务器准备好以后,就可以接受来自前端浏览器的网页访问请求了。
我们先来看一下浏览器访问网站的完整流程:

处理浏览器请求的框架
因为可能有多个用户同时发起请求,为了更快的处理网页请求,这里使用多线程技术。流程如下:

服务端收到浏览器的请求后,accept函数会返回一个“客户端套接字”,这个套接字对应于这个浏览器客户端。以后服务器就通过这个“客户端套接字”和对应的浏览器通信。此时,服务器端有两种套接字:
服务器端套接字:用来等待新的浏览器客户端的发起请求,收到请求后,返回一个客户端套接字。
客户端套接字:用来和对应的浏览器客户端通信。每个浏览器客户端连接到服务器后,都有一个对应的客户端套接字。
具体代码实现如下:

处理浏览器的请求
在新线程中,单独处理对应浏览器客户端的请求。
GET请求报文的格式
浏览器发起新的访问时,将向服务器端发送一个请求报文。例如,在浏览器地址输入 127.0.0.1:8000 回车后,服务器端收到的完整报文如下:

请求报文由4四个部分组成:请求行、请求头部行、空行、请求数据。具体格式如下:

第一行报文详细说明

响应报文的格式
服务器发送数据给浏览器时,发送的响应报文,由4个部分组成:
状态行、消息头部、空行和响应正文。格式如下:

常用的关键字有:

POST请求报文的格式
浏览器发送的POST报文的格式,和GET报文格式其实是一致的,只是多了最后一部分内容“请求数据”,实例如下:

最后一行“color=red”就是网页提交的数据。
报文的解析(每行代码的详细说明,可参考本教程的分享视频)





发送错误请求的响应包
发送501未实现服务的响应包
HTTP 状态码分为 5 类,如下所示:
1xx 信息
2xx 成功
3xx 重定向
4xx 客户端错误
404 表示服务器找不到浏览器请求的资源(例如某个图片或某个文件)。
5xx 服务器错误
501 表示服务器现在还不能满足客户端请求的某个功能。
代码如下:

注意代码中的Server关键字,表示服务器端的软件名称和它的版本号。
发送404资源不存在的响应包
代码如下:
