一、前言
本文的主要目标是用C++实现一个webServer,但在实现一个WebServer的前提下,我们首先需要知道什么是WebServer。
它其实很简单,当你浏览到本页面时,就已经在访问一个webServer了。
到目前为止,我想你应该对TCP与UDP协议已经不陌生了,并且已经能够用它们进行熟练的编程了。
比如写一个简单的聊天室,应该没问题了吧?如果还不会,本站的其它文章:网络编程详解
一个Web服务器,其本质也是一个服务器,底层使用的协议就是TCP协议。
也就是说,我们想要手写一个Web服务器,实际上是在手写一个TCP服务器而已。
这么一说,是不是就觉得
web服务器其实也不那么神秘了!
但既然它有了一个新名字,那必然就与普通的TCP服务器有所差别。
而其差别就在于:web服务器需要遵守一定的规则来 发送/接收 字符串,这个规则就叫做:HTTP协议
拿一个最简单的例子来说,当你想要看到本页内容,首先就需要先得到本页内容在本站服务器上的路径,也就是当前你的浏览器上方的那个链接。
以这个本站主页链接举例:https://www.kucoding.com/
有了这个链接,将其复制到网址栏,按下回车,你的浏览器就会作为一个TCP客户端,向本站点的服务器发送一个连接请求。
这里大家可能有个疑问,那就是我们平时编程时都用的ip地址与端口号进行连接的,这里也没看到这两个东西呀?
其实是有这两个东西的。
比如IP地址,浏览器会先发送一个请求获取域名www.kucoding.com的ip地址,也就是完整链接中间那一段,只是ip地址对我们来说是不可见的。
而端口,由于http协议默认为80端口,https默认为443端口,所以也给我们省略了
这个域名怎么来的?那就需要自己去购买了,一般都是几十块一年,购买后,绑定到自己的ip地址,这样你就也能通过域名来访问你的ip地址了。
这里同样提到了另一个https协议,是在http的基础上添加了一个s,即安全层(Secure)。
因为前面提到了,http是通过服务器与客户端直接发送一定规则字符串实现的,所以很容易被人拦截直接看到其中传输的内容,因此需要添加一个安全层,也就是先加密,再传输,到达之后再解密。
举个实际的例子,还是以上面那个链接为例,我们可以通过ping命令获取到本站点服务器的ip地址:

然后将这个链接前面那串域名替换为这个ip地址:https://43.134.72.180:443/
并在ip地址后面添加上了端口号443,中间用:分隔:43.134.72.180:443
然后直接在浏览器上访问这个链接:

可以看到,:443会被自动省略掉,并且禁止访问
这是因为https多了一个安全层,需要对域名进行校验,但我们这里直接用的ip地址访问,没有域名,校验失败,就出现了错误(如果是http协议,那么就不会有这个问题了)
二、HTTP协议基础
现在,我们已经知道了web服务器实际上就是一个发送与接收固定规则字符串的TCP服务器
那么下一步我们需要知道的就是,这个规则是什么?
实际上的规则很简单,对于客户端而言,其固定协议如下面所示:
Method URL HTTP/Version
Header1: Value1
Header2: Value2
Body
首先是方法:Method
一般我们浏览器网页,用到的都是GET方法,即获取的意思,本文也将以GET方法为例子作为讲解。
然后是URL,即资源路径,比如前面提到的那个链接:https://www.kucoding.com/
那么其资源链接就为最后的/,即空就是根目录的意思,这种一般由开发者指定一个默认文件资源,一般名字为index.html。也就是说,https://www.kucoding.com/和它https://www.kucoding.com/index.html大部分时候都是一个意思。
然后是HTTP协议的版本号,目前使用的大部分还是1.1版本,所以就统一为:HTTP/1.1。
紧接着就是一连串的键值对,叫做请求头,前面的Header有一系列专用的名称,后面的Value就是对应的值。
比如有时候你会发现,手机和电脑访问同一个网站,怎么展现出来的内容就不一样呢?
这便是通过User-Agent这个键来进行识别的,比如我的浏览器就会自动发这个键给服务器:

服务器就会通过这个来识别当前我们用的设备、浏览器版本之类的东西。
然后中间以一个空行作为分隔,后面的Body为请求体,但由于GET请求不需要,所以就没有它。
但服务器要响应这个GET请求时,却需要将要显示的网页内容通过响应体发送回来,只是叫法不同,实际上两者都指的是这个Body。
服务器协议为:
HTTP/版本号 状态码 状态信息
响应头信息
响应体
只有第一行与客户端不同,其它都一样的,下面一个实例举例子:
比如GET请求index.html页面:
