我曾七次鄙视自己的灵魂
第一次
当它本可进取时
却故作谦卑
—— 纪伯伦《我曾七次鄙视自己的灵魂》
OSI七层网络模型
七层网络模型是网络理论的基础,单靠死记硬背并不那么轻松,很容易搞混,重要的还是理解为什么这样设计分层。
TCP与UDP
它们同属于传输层Transport的协议。
TCP的三次握手与四次挥手
TCP建立连接需要经历三次握手,断开连接需要经历四次挥手。它是一种面向连接的协议,基于虚拟的管道进行通信。
对于三次握手通俗的解释如下:
- 客户端通知服务器,我已准备好,尝试向你建立连接(类型为
SYN=1,值为seq=x) - 服务器收到客户端的请求,并通知客户端,我已收到你的数据(类型为
ACK=1,值为ack=x+1),现在请确认你是否可以收到我的数据(类型为SYN=1,值为seq=y) - 客户端再次通知服务器,我可以收到你的数据(类型为
ACK=1,值为ack=y+1)。双方进入ESTABLISHED状态
建立连接后,双方进行数据传输。当双方同处于ESTABLISHED状态下,完成数据传输后,可以进行四次挥手,通俗解释如下:
- 客户端判断自己已经获取到全部想要取得的数据,通知服务器我想要断开连接(类型为
FIN=1,值为seq=u) - 服务器收到请求后,立即发出确认报文(类型为
ACK=1,值为ack=u+1,同时传递seq=v)。此时客户端->服务器这条方向的连接被释放,客户端主机已经不再有数据发送;但服务器->客户端这条方向的数据可能仍处于传输中 - 当服务器不再有数据传输时,服务器通知客户端我已经把数据全都传完了(报文类型为
FIN=1,值为seq=w,同时类型为ACK=1,ack=u+1)。注意此时seq=w与第二次挥手中的seq=v不一定相等,因为二三次挥手之间可能又传输了一些数据 - 客户端收到服务器发来的报文,通知服务器断开连接(类型
ACK=1,值为ack=w+1,同时seq=u+1)
可以看到四次挥手分成两部分,分别是客户端->服务器尝试断开连接的报文来回,以及服务器->客户端确认断开连接的报文来回。
TCP是面向连接的,数据正式传输前需要建立一条虚拟连接,数据的传输在这条虚拟连接上进行,并且完成传输后需要断开连接。而UDP传输不面向连接,并且,UDP不关心接收方的接收状态。
TCP与UDP的差异
这两个传输层协议在可靠性、有序性、报文结构、传输效率方面有所差别。
可靠性差异
可靠性即指发送方是否保证数据传输到,以及发送方是否知悉发送结果。TCP是可靠的传输层协议,UDP则不可靠。
TCP通过应答号ACK和序列号SEQ来保证可靠性。首先说应答信号ACK,当发送方发送数据后,必须等待接收方返回ACK信号,如果经过一段时间没有收到对方返回的ACK信号,则发送方判断此次发送失败,会进行重试。
此过程中有两个地方可能导致发送方收不到ACK信号,分别是发送数据传输失败,和ACK信号传输失败,在发送方看来这都是发送失败,都需要进行重试。
发送失败
ACK失败
我们假设一个场景,发送方发送了一条数据A出去,此时由于网络环境波动,传输速率下降,导致经过超时时间仍未返回ACK信号。此时发送方认为自己发送失败了,再次发送同一条数据A'过去,但网络恢复后,接收方会同时收到A、A'两条“相同”的数据。对于接收方而言,又要如何判断采纳哪一条、抛弃哪一条?这种现象称为“延迟到达”。
这就是序列号SEQ的用武之地,发送方在发送数据时,会按照数据本身字节的顺序,为报文增加一个序列号U;接收方在收到数据并回文ACK时,同样携带一个序列号U+1,表明我已收到你发来的U,接下来请发送U+1的数据。对于延迟到达的情况,接收方收到两个相同的数据包,自然可以根据序列号保留它所需要的正确的那个。
有序性差异
TCP协议在传输数据时,接收方会根据序列号SEQ对收到的报文进行重排,从而保证接收的有序性。而UDP则不具备这些机制,这是两者在有序性上存在的巨大差异。
报文段差异
作为传输层Transport协议,传输的数据统称为报文段。
UDP报文段
- 源端口号(Source Port): 这个字段占据 UDP 报文头的前 16 位,通常包含发送数据报的应用程序所使用的 UDP 端口。接收端的应用程序利用这个字段的值作为发送响应的目的地址。这个字段是可选项,有时不会设置源端口号。没有源端口号就默认为 0 ,通常用于不需要返回消息的通信中
- 目的端口号(Destination Port): 表示接收端端口,字段长为 16 位
- 长度(Length): 该字段占据 16 位,表示 UDP 数据报长度,包含 UDP 报文头和 UDP 数据长度。因为 UDP 报文头长度是 8 个字节,所以这个值最小为 8,最大长度为 2 ^ 16 = 65535 字节
- 校验和(Checksum):UDP使用校验和来保证数据安全性,UDP的校验和也提供了差错检测功能,差错检测用于校验报文段从源到目标主机的过程中,数据的完整性是否发生了改变
TCP报文段
相比于UDP,TCP的报文结构上增加了一些用来保证可靠性、有序性的字段。
- 32 比特的序号字段(sequence number field) 和 32 比特的 确认号字段(acknowledgment number field) 。这些字段被 TCP 发送方和接收方用来实现可靠的数据传输。
- 4 比特的首部字段长度字段(header length field),这个字段指示了以 32 比特的字为单位的 TCP 首部长度。TCP 首部的长度是可变的,但是通常情况下,选项字段为空,所以 TCP 首部字段的长度是 20 字节。
- 16 比特的接受窗口字段(receive window field) ,这个字段用于流量控制、拥塞控制。它用于指示接收方能够/愿意接受的字节数量
- 可变的选项字段(options field),这个字段用于发送方和接收方协商最大报文长度,也就是 MSS 时使用
- 6 比特的标志字段(flag field), ACK 标志用于指示确认字段中的值是有效的,这个报文段包括一个对已被成功接收报文段的确认;RST、SYN、FIN 标志用于连接的建立和关闭;CWR 和 ECE 用于拥塞控制;PSH 标志用于表示立刻将数据交给上层处理;URG 标志用来表示数据中存在需要被上层处理的 紧急 数据。紧急数据最后一个字节由 16 比特的紧急数据指针字段(urgeent data pointer field) 指出。一般情况下,PSH 和 URG 并没有使用。
效率差异
UDP发送的报文段是不需要确认的,传输效率相对较高。
TCP则引入了用来解决性能问题的“窗口”概念,在往返时间较长、频次较多的情况下,可以克制网络性能带来的传输速率下降。
滑动窗口是用来一次发送多个报文段的容器,在一个窗口中的报文可以不经确认应答便持续发送,在窗口的缓冲区中,记录了发送出去的报文,当有确认请求回来时,将相对应的请求从缓冲区移除。
如果窗口中的某个请求失败,整个缓冲区会进行重新发送。
笔者:不确定,这样效率难道不会降低吗,为啥不单独重试?
使用场景差异
TCP协议的使用场景
- 对传输可靠性有要求:HTTP协议
UDP协议的使用场景
- 对传输速率有要求:Ping、DNS Lookup、视频流、即时通讯
在即时通讯场景下,如何避免UDP带来的丢包、时序问题
以QQ为例,QQ采用的通信协议以UDP为主,TCP为辅。由于UDP本身不是可靠的传输协议,QQ采用了上层协议来保证数据传输的可靠性:如果客户端使用UDP协议发出消息后,服务器收到该包,需要使用UDP协议发回一个应答包,如此来保证消息可以无遗漏传输。之所以会发生在客户端明明看到"消息发送失败"但对方又收到了这个消息的情况,就是因为客户端发出的消息服务器已经收到并转发成功,但客户端由于网络原因没有收到服务器的应答包引起的。
QQ 并不是端对端的聊天软件,是得经过服务器转发消息的,通过 QQ 聊天,数据是 A 发到服务器,服务器再转发到 B。
HTTP与HTTPS
它们都是应用层协议,定义了客户端与服务器之间响应的模型。客户端与服务器的角色是不固定的,取决于在一次数据传输中,谁担任发送者,谁担任接收者。
HTTP 超文本传输协议 Hyper Text Transport Protocal
HTTP协议建立在传输层协议TCP之上,客户端通过与服务器建立TCP连接,之后发送HTTP请求与接收HTTP响应都是通过访问Socket接口来调用TCP协议实现。
HTTP目前已经演化到3.0版本,它们中高版本是向下兼容低版本的。
- HTTP/0.9:已过时。只接受 GET 一种请求方法,没有在通讯中指定版本号,且不支持请求头。由于该版本不支持 POST 方法,所以客户端无法向服务器传递太多信息。
- HTTP/1.0:这是第一个在通讯中指定版本号的 HTTP 协议版本,至今仍被广泛采用,特别是在代理服务器中。可以支持POST、HEAD方法,支持HTML文件以外的其他类型,但不支持持久连接。
- HTTP/1.1:引入了持久连接,即TCP连接默认不关闭,可以被多个请求复用,能很好地配合代理服务器工作。还支持管道方式机制,即在同一个TCP连接里面,客户端可以同时发送多个请求,以便降低线路负载,提高传输速度。
- HTTP/2.0:完全多路复用,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应。引入了头信息压缩机制,使用gzip或compress压缩后再发送。支持服务端推送,允许服务器未经请求,主动向客户端发送资源。
- HTTP/3.0:不用TCP作为传输层协议,使用基于UDP的QUIC(Quick UDP Internet Connections)协议。QUIC集成了TLS加密、流量控制、多路复用等功能,并在用户空间实现了快速连接建立、前向纠错、更精细的拥塞控制等特性。采用TLS1.3作为默认安全层协议,提供更强的安全性。
HTTP协议的特点
注意,这些特点是HTTP、HTTPS协议所共有的,因为HTTPS就是基于HTTP增加了安全机制。
- 支持客户端/服务器模式
- 简单快速:客户向服务器请求服务时,只需传送请求方法和路径
- 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记
- 无连接:限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间
- 无状态:协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即我们给服务器发送HTTP请求之后,服务器根据请求,会给我们发送数据过来,但是,发送完,不会记录任何信息
HTTP状态码
| 状态码 | 含义 | 举例 |
|---|---|---|
| 1XX | 信息提示 | |
| 2XX | 正常 | 200 |
| 3XX | 重定向 | 301永久,302临时 |
| 4XX | 客户端错误 | 401用户密码错误,403访问被拒绝,404文件不存在 |
| 5XX | 服务器错误 | 501服务器内部错误,502无效网关,504网关请求超时 |
HTTPS 安全套接字层超文本传输协议 Hyper Text Transport Protocal Secure
HTTPS是在HTTP的基础上在HTTP和TCP之间又加入了SSL/TLS协议,通过这个协议可以验证服务器的真实身份,也可以对数据传输进行加密保证它的安全性。需要CA证书,且端口变为443(HTTP端口是80)。
私钥、公钥、对称/非对称加密
私钥与公钥是非对称加密用到的概念:
- 公钥:在加密过程中,用于编码数据;在签名过程中,用于验证签名
- 私钥:在加密过程中,用于解码数据;在签名过程中,用于生成签名
在对称加密中,加密&解密使用同一个密钥,一旦这个密钥泄漏,传输的数据就相当于变为明文。而在非对称加密中,即使泄漏了公钥,只要私钥仍然有效,服务器的身份就还是安全的。私钥的存在可以保证服务器大盘的安全性。
HTTPS流程
- 客户端发起HTTPS请求,连接到服务器的443端口。
- 服务器必须要先申请好一套数字证书(证书内容有公钥、证书颁发机构、失效日期等)。
- 服务器将自己的数字证书发送给客户端(公钥在证书里面,私钥由服务器持有)。
- 客户端收到数字证书之后,会先验证证书的合法性。如果证书验证通过,就会使用伪随机数生成器(/dev/random)随机生成一个【对称密钥】,使用证书的公钥加密这个【对称密钥】。
- 客户端将公钥加密后的【对称密钥】发送到服务器。
- 服务器接收到客户端发来的密文密钥之后,用自己之前保留的私钥对其进行非对称解密,解密之后就得到客户端的【对称密1. 钥】,然后用客户端的【对称密钥】对返回数据进行加密,这样传输的数据都是密文了。
- 服务器将加密后的密文数据返回到客户端。
- 客户端收到后,用自己的【对称密钥】对其进行对称解密,得到服务器返回的数据。
HTTP与HTTPS的区别
- HTTP 是明文传输协议,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
- HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,谷歌、百度优先索引HTTPS网页;
- HTTPS需要用到SSL证书,而HTTP不用【(HTTPS是安装SSL的服务器,HTTP是未安装SSL的服务器)】;
- HTTPS标准端口443,HTTP标准端口80;
- HTTPS基于应用层+表现层+传输层,HTTP基于应用层+传输层;
- HTTPS在浏览器显示绿色安全锁,HTTP没有显示。