一、前言
本文的主要目标是用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
页面:
GET /index.html HTTP/1.1
Accept: text/html
这个的请求头我只写了一个Accept
,即客户端可接受的资源类型,为text/html
,即html文本
,没有请求体
然后我们的服务器就可以发出响应了:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
<html><body>Hello World</body></html>
200
为正常状态码,OK
为正常状态消息。
很多时候我们还能看到404
,301
等等状态码,实际上就是服务器返回给我们看的,都有其对应的含义,可以在浏览器中搜索了解。
Content-Type
指代我们发送内容的信息,为html
文档,然后字符集charset
为UTF-8
编码,后面的响应体就是我们的html
代码了。
三、C++代码实战
有了上面的基础,下面我们就可以用C++来实现一个简单的WebServer
服务器,让我们的浏览器可以访问它!
因为大部分人用的应该都是VS
,所以我这里也还是以VS环境作讲解。
前面一系列的初始化、创建socket
、绑定、监听等内容我也就不在赘述了,如有不懂的可以查看本专栏前面网络部分相关的文章。
直接来到关键部分:
// 处理客户端请求
while (true) {
// 接受客户端连接