1. 手写一个WebServer

一、前言

本文的主要目标是用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地址:

image-20230914103602541

然后将这个链接前面那串域名替换为这个ip地址:https://43.134.72.180:443/

并在ip地址后面添加上了端口号443,中间用:分隔:43.134.72.180:443

然后直接在浏览器上访问这个链接:

image-20230914103904086

可以看到,: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为正常状态消息。

很多时候我们还能看到404301等等状态码,实际上就是服务器返回给我们看的,都有其对应的含义,可以在浏览器中搜索了解。

Content-Type指代我们发送内容的信息,为html文档,然后字符集charsetUTF-8编码,后面的响应体就是我们的html代码了。

三、C++代码实战

有了上面的基础,下面我们就可以用C++来实现一个简单的WebServer服务器,让我们的浏览器可以访问它!

因为大部分人用的应该都是VS,所以我这里也还是以VS环境作讲解。

前面一系列的初始化、创建socket、绑定、监听等内容我也就不在赘述了,如有不懂的可以查看本专栏前面网络部分相关的文章。

直接来到关键部分:

    // 处理客户端请求
    while (true) {
        // 接受客户端连接
作者:余识
全部文章:0
会员文章:0
总阅读量:0
c/c++pythonrustJavaScriptwindowslinux