9.1 计网速通
Author: 柏喵樱
copyright reserved
计算机网络是一个非常复杂的系统。在这一章节中,系统的底层实现将被隐去,只留下暴露给用户的内容。
这一章节为 Web 开发入门设计,用于速通 Web 开发和计网的交叉知识,故命名为 “计网速通”。
IP 地址与端口
1.1.1.1:80
如你所见,上面一串字符表示一个 IP 和端口,他的格式是 IP:端口
IP 是一个由小数点分割成四段的序列,每段数字的取值为 1.1.1.1
而端口是一个数字,取值范围是80
所有在互联网上的计算机都会被分配到一个 IP,用于标识自己。
现在先抛开具体的实现方式不提,给你一个既定的事实:互联网能够将数据从一个 IP 地址传递到另一个任意的 IP 地址。
现在你已经知道了怎样使用互联网传送数据,先不讨论怎么说,理论上说只需要知道对方的 IP,给他发数据就可以了。
那么端口是干什么用的呢?
想象你的电脑上有很多的应用程序,他们都往互联网上同一个服务器发数据,互联网上的这个服务器也给他们回复数据。当接受到的所有的数据都到了操作系统手里,此时,操作系统如何知道,哪些个数据应该给哪些个应用程序?
解决方案也很简单,给发出的数据打一个 “标记”,这个标记就是端口(Port)。
想象一个港口,里面有很多的码头,一个应用程序他可以接管一个码头,用于自己传输数据。
我们可以从一些数据从 IP 地址 1.1.1.1 的 54321 号码头发送数据到 IP 地址 2.2.2.2 的 12345 号码头,同时在发送的数据上做标记,标记他来自什么地方的几号码头。回复数据的时候自然知道往什么地方回复了。
上面的描述也就是
1.1.1.1:54321 -> 2.2.2.2:12345
即,将数据从 1.1.1.1 的 54321 端口发送到 2.2.2.2 的 12345 端口
可以说这个数据包有以下属性
- 源 IP 1.1.1.1
- 源端口 54321
- 目的 IP 2.2.2.2
- 目的端口 12345
TCP 与 UDP
TCP 和 UDP 两个协议的具体实现都是由操作系统提供的,应用程序发送 TCP 包和 UDP 包一般都是使用操作系统的 API 发送的,所以我们无需关系这两个协议的具体实现细节。
下面通过表格对比两个协议来告诉大家如何选择去使用哪一个协议。
TCP | UDP | |
---|---|---|
可靠性 | 有 | 无 |
速度 | 慢 | 快 |
表格很小,但是最本质的区别就是这些了。
TCP 的最大特点就是可靠交付,他有一个 ACK 确认机制,简单来说就是对于发送的数据,如果没有收到对方的 ACK 确认收到,他会不断尝试重发,直到他认为无法送达。
UDP 和 TCP 虽然经常一起被提起,也确实属于互联网的同一个层,但从他们的复杂度看,他们并不是两个对等的协议。比起 TCP 有一套非常复杂的算法实现可靠交付流量控制等协议,UDP 真的就是单纯发了一个数据包过去,然后什么也不管。
不过不用担心,大家也没多少机会直接接触这两个协议,还是接触 HTTP 居多。如果真的需要做出选择,除非你知道你在做什么,选 TCP。
现在,你应该知道,虽然你不知道具体怎么做,但是从理论上说,你可以选择其中一种协议发送数据到另一台联网的计算机的某个端口上。
如果此时这台计算机的某个应用程序在这个端口使用了正确的协议监听,这个程序他能够正确地获取到数据。两个程序之间的点对点(p2p)通信就这样建立了。
DNS
DNS (Domain Name System) 域名系统
目前我们已经能够和服务器建立起可靠的连接了,但这与我们日常所见的并不一样。
对于日常使用,如果我要打开一个网页,我会选择使用比如 bilibili.com
这样的东西,这一串字符叫做域名
域名的最直观用途是代替你记忆 IP 地址,当你访问 bilibili.com
这个网址的时候,一般首先会调用操作系统 API,操作系统会代替你发送域名解析请求到 DNS 服务器,最后 DNS 服务器会返回给你域名对应的 IP 地址。
其实你也可以拥有自己的域名这很简单。如果你要搭建你自己的网站,购买域名是逃不掉的,在国内的话还需要备案。
如上图所示,一个域名有很多不同的解析类型,但是目前你只需要知道 A 记录是什么。
A 记录是目前互联网上最主要的记录类型,他的记录值是一个 IPv4 地址(就是上述的 IP,v4 是版本号)。
举个例子,域名 aaa.bbb.cn
做 A 解析到 1.1.1.1
,我们需要设置:
- 主机记录 aaa
- 记录类型 A
- 记录值
1.1.1.1
- 其他默认
此时如果你如果将这个域名作为网址使用,浏览器就会通过域名解析拿到 1.1.1.1
,向 1.1.1.1
发送 HTTP 请求获取数据
HTTP
HTTP 协议用于 WEB 服务器,一般多见于浏览器获取网页内容。浏览器会用 HTTP 协议发送 HTTP 请求到服务器,服务器处理 HTTP 请求并返回 HTTP 响应。很多的 APP,小程序和电脑上的应用程序都在广泛地使用 HTTP
HTTP 协议有不少版本,现在互联网上最流行的是 HTTP/1.1 版本,浏览器一般最高支持 HTTP/2.0, 最新版本是 HTTP/3.0, 下面只讨论 HTTP/1.1
HTTP 的底层是 TCP,他基于此规定了一套文本格式,用于表达一些信息
单纯说说是说不明白的,HTTP 报文分请求和响应两种格式,下面给出实例
如果你有兴趣做 HTTP 抓包,推荐用 Yakit,本人实习正在做这个产品,也欢迎反馈 bug
请求
POST /x/click-interface/web/heartbeat HTTP/1.1
Host: api.bilibili.com
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Content-Length: 397
Content-Type: application/x-www-form-urlencoded
Cookie: balh_server_inner=__custom__;dy_spec_agreed=1; balh_is_closed=; PVID=1; i-wanna-go-back=-1; CURRENT_BLACKGAP=0; buvid_fp_plain=undefined; DedeUserID=74145050; DedeUserID__ckMd5=a31c4db0fb996454; blackside_state=0; b_nut=100;
Origin: https://www.bilibili.com
Referer: https://www.bilibili.com/video/BV1Kx4y1Z7xb/?vd_source=9ec246e4a5695e749fc2f84871669501
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188
sec-ch-ua: "Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
start_ts=1690809334&mid=74145050&aid=998480789&cid=1195467370&type=3&sub_type=0&dt=2&play_type=4&realtime=27&played_time=27&real_played_time=35&refer_url=https%3A%2F%2Fmember.bilibili.com%2F&quality=0&video_duration=186&last_play_progress_time=27&max_play_progress_time=27&spmid=333.788.0.0&from_spmid=&extra=%7B%22player_version%22%3A%224.2.4-rc.2132.0%22%7D
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
所见即所得,除了部分敏感字段被隐去外,HTTP 报文在网络中传输时,就长这样
请求方法
首先看到第一行
POST /x/click-interface/web/heartbeat HTTP/1.1
POST
是请求方法,具体如何使用没有明确的规定,可以参考 Restful 风格,Restful 规定的请求方法有
- GET
- POST
- PUT
- DELETE
分别对应查,增,改,删四个动作,这四个动作统称增删查改,英文 CRUD(Create Read Update Delete)
其中,一般来说 GET 和 DELETE 两个请求方法是不带负载 (后面有讲什么是负载) 的,但这也不是硬性规定。
如果你从浏览器地址栏打开一个网页,那么他首先会向对面服务器发送一个 GET 请求,而其他类型的请求往往是网页加载过程中 js 脚本向服务器获取数据所带来的的。
请求路径 HTTP 版本号
早期的 Web 服务器采用纯静态 + 文件目录结构,这其实相当于说暴露一个文件夹在互联网上,然后大家使用文件路径获取这个文件夹中的一个特定的文件。
这个格式一直以来都得到了沿用,现代的路径早已经失去了这个固定意义,成为了一种分类和标识。
请求路径可以带请求参数的,上面的例子没有展现出来,类似于
/shell?cmd=ls&a=b
这种写法只是一种所有人都遵循的格式,这样的路径带 2 个参数,第一个名字叫 cmd
,参数的值是 ls
,第二个名字叫 a
,参数的值是 b
。
如果出现字符冲突,比如你需要一个参数值为 &
的参数,可以使用 URL 编码,写成 %26
,这是 %+16进制ascii码
的格式。
这一行最后跟一个 HTTP 版本号
请求头(header)
紧接着的是请求头,其固定格式为 Key: Value
一行一个请求头,不同的请求头有不用的用途,广泛认可的请求头有
- Host 主机名,也就是域名,如果使用 IP 访问,这里会写成 IP
- Content-Type 表示 Payload 的内容格式
- User-Agent 发 HTTP 包的人用的浏览器类型和版本号
- Cookie 用于存储认证信息等,由服务器设置,浏览器每次请求都会携带
别的可以暂时不知道
请求头也可以自定义,如果你觉得有必要你可以添加你自己的请求头
负载(payload)
上面的实例是一个 application/x-www-form-urlencoded 类型的 payload,这由 Content-Type 规定。他的格式和请求参数是一致的。
负载还有很多种不同的格式,比如 json,xml,form-data Web 开发那一块应该会讲,这里就不提了。
响应
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin,No-Cache,X-Requested-With,If-Modified-Since,Pragma,Last-Modified,Cache-Control,Expires,Content-Type,Access-Control-Allow-Credentials,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Cache-Webcdn,x-bilibili-key-real-ip,x-backend-bili-real-ip,x-risk-header
Access-Control-Allow-Origin: https://www.bilibili.com
Access-Control-Expose-Headers: X-Bili-Gaia-Vvoucher
Bili-Status-Code: 0
Bili-Trace-Id: 014a52764364c7b4
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Cross-Origin-Resource-Policy: cross-origin
Date: Mon, 31 Jul 2023 13:17:39 GMT
X-Bili-Trace-Id: 369754a5d2179290014a52764364c7b4
X-Cache-Webcdn: BYPASS from blzone03
Content-Length: 51
{
"code": 0,
"message": "0",
"ttl": 1
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
协议版本 响应状态码
协议版本不提了
响应状态码有很多种
上面响应了 200 OK 这是最主要的一种对于请求成功的响应,其他常见的有
- 500 服务器内部错误
- 404 服务器找不到资源
- 403 没权限
- 301 永久跳转
- 302 暂时跳转
- 200 成功返回
其中跳转类型会附带 Location 响应头,响应头的内容是要跳转到的地方
响应头
格式和请求头保持一致
在实例的响应头中可以看到很多由 Bilibili 自定义的响应头
其他和请求头基本一致不做讲解
负载 (payload)
这是一个 json 格式的负载,具体参考 Web 开发章节
TLS
现在大多数的网址都会使用 HTTPS 协议而不是 HTTP,其区别在于,HTTP 是把上面提到的报文直接放在 TCP 里传输,此时如果有人抓包获取了你的报文,他是可以看到完整内容的。为了安全,TLS 诞生了。
HTTPS 的本质就是在将 HTTP 报文通过 TLS 进行发送,而不是直接通过 TCP 发送。
TLS 建立在 TCP 的基础上,他会通过加密来确保传输过程中数据的安全。
具体如何加解密在这里不讨论,比较复杂,这里只能指条路:服务器想要处理 TLS 握手构建安全传输,服务器需要证书和秘钥。这两个东西是由证书签发机构签发的,免费的证书签发机构最出名的是 Let's Encrypt,签发证书最方便的脚本是 acme.sh。
常用协议端口
我们在打开一个网页的时候,是不是从来没有考虑过端口的问题?
这是因为 HTTP/HTTPS 协议有个默认端口,分别是 80 和 443,不写就是默认端口
下面给一个常用端口列表,随便记一下差不多了
应用层协议 | 端口 | 传输层实现 |
---|---|---|
FTP | 21 | TCP |
SSH | 22 | TCP |
SMTP | 25 | TCP |
DNS | 53 | UDP |
HTTP | 80 | TCP |
POP3 | 110 | TCP |
HTTPS | 443 | TCP |
Mysql | 3306 | TCP |
RDP | 3389 | 默认 UDP |
Redis | 6379 | TCP |
公网与内网 --- 真实环境分析
基本的内容介绍的差不多了,下面分析一个简单的网络案例,顺带介绍公网和内网的概念。
相信在看这篇文章的大家都正在使用互联网,如果你正在使用 windows 设备,你可以先按 win
+ R
,输入 cmd
,在弹出的窗口输入 ipconfig
你可以看到里面有一串类似于下文的内容:
无线局域网适配器 WLAN:
连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::4835:c258:e07d:acc3%24
IPv4 地址 . . . . . . . . . . . . : 192.168.0.109
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.0.1
2
3
4
5
6
7
IPv4 地址一栏有一个形似 192.168.XXX.XXX
的地址,这是一个典型的内网地址,类似的还有很多,比如说
- 192.168.0.0 - 192.168.255.255
- 10.0.0.0 - 10.255.255.255
- 172.16.0.0 - 172.31.255.255
看到以上任意一个都是非常合情合理的,虽然还有其他内网地址,但是那些都比较冷门,可能一辈子碰不到,不用记忆。
因此,除了上面列出的 IP 地址,请将他们一律视为公网地址,公网地址是独一无二的,绝对的,内网地址在不同的子网里可以重复使用,是相对的。
此外下面还有子网掩码和默认网关,掩码会在后续的内容中介绍,现在知道你只需要知道:
- 上面显示的
IPv4 地址
是你这台设备的 IP 地址 - 家庭和寝室网络子网掩码默认
255.255.255.0
- 默认网关是路由器在内网的 IP,你的设备需要路由器的帮助将数据包从内网转发到公网
此刻你可能会有一个疑问,作为一台联网的计算机设备,我可以把数据发送到公网的服务器上,因为我知道他的公网 IP,而且这是独一无二的,只要我联网,互联网上的路由设备会尽力帮我把数据送到地方。
但是,返回的数据该怎么办?
显然,对面不可能把数据包发给一个内网地址,他只有发给一个公网地址,互联网上的路由设备才知道他要去哪,才能帮他将数据送到地方。
问题的答案很简单,我们的路由器,他通过 PPPoE 拨号的方式向运营商拿到了一个公网 IP。他在把数据包转发到互联网上前,做了一个网络地址转换的操作,把数据包的源地址替换成了他的公网 IP,再找了一个随机端口号,在那里将修改后的数据发送到公网,这个转换的操作会被路由器记录。
这样,公网上的服务器在收到数据包后也能知道,这个包来自于哪个公网 IP 的哪个端口,回复的时候就知道发到什么地方了。
路由器拿到公网上的服务器回复的数据包后,可以根据做网络地址转换时的记录,逆向推导出他应该将包发送到内网的哪台机器的哪个端口,就完成了数据的收发。
绝大多数的家庭或者寝室网络都遵循着这个规则。
那为什么要这么做呢?
对于一般家庭网络,有两个简单的理由
- 安全,只有你主动连接才能拿到回复,互联网上的设备无法主动访问你的设备
- IPv4 不够用啦
其他特殊 IP 地址
- 127.0.0.1 本机,用于自己的设备给自己的设备另一个端口发送数据
- 169.254.x.x 保留地址,向路由器获取内网地址前会临时使用这个地址,如果你发现你的电脑正在使用这个地址,路由器可能坏了
- 198.18.x.x 保留地址,但是有些软件会使用这个地址来实现透明代理(tun)
好,我们的计网速通章节,到此结束,这些计算机网络知识应该足够你做简单的 Web 开发了