# 9.1计网速通 > Author: 柏喵樱 > > copyright reserved 计算机网络是一个非常复杂的系统。在这一章节中,系统的底层实现将被隐去,只留下暴露给用户的内容。 这一章节为 Web 开发入门设计,用于速通 Web 开发和计网的交叉知识,故命名为 “计网速通”。 ## IP 地址与端口 `1.1.1.1:80` 如你所见,上面一串字符表示一个 IP 和端口,他的格式是 `IP:端口` IP 是一个由小数点分割成四段的序列,每段数字的取值为 $[0,255]$ , 在上面的示例中,IP是`1.1.1.1` 而端口是一个数字,取值范围是$[0,65535]$ , 在上面的示例中,端口是`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地址。 其实你也可以拥有自己的域名这很简单。如果你要搭建你自己的网站,购买域名是逃不掉的,在国内的话还需要备案。 ![域名解析后台](/9.计算机网络/static/dnspod-domain.png) 如上图所示,一个域名有很多不同的解析类型,但是目前你只需要知道 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 ### 请求 ``` http 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 ``` 所见即所得,除了部分敏感字段被隐去外,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 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 } ``` #### 协议版本 响应状态码 协议版本不提了 响应状态码有很多种 上面响应了 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 | ## 参考资料 - HTTP 教程