- 传输层概述与UDP 需求/服务/协议、多路复用/分解、UDP协议
- 可靠传输 可靠传输基础知识、TCP可靠传输
- TCP 报文段结构、超时间隔、流量控制、连接管理
- TCP拥塞控制 网络拥塞、TCP拥塞控制、吞吐量分析
传输层概述
应用层需求 | 传输层服务 | UDP | TCP |
---|---|---|---|
为运行在不同主机上的进程之间提供逻辑通信 | 进程间交付 | ✓ | ✓ |
检测报文段是否出错 | 差错检测 | ✓ | ✓ |
解决去包、差错问题 | 可靠传输 | × | ✓ |
解决乱序问题 | 按序交付 | × | ✓ |
解决接收缓存溢出问题 | 流量控制 | × | ✓ |
应对网络拥塞 | 拥塞控制 | × | ✓ |
可靠传输
GBN(Go-Back-N)
发送方
- 初始化一个大小为 N 的滚动窗口,其中
base
表示窗口的起始序号,nextSeqNum
表示下一个要发送的序号。 - 发送窗口内的数据包,并更新
nextSeqNum
。 - 当
nextSeqNum
达到base + N
时,开启定时器。 - 收到 ACK 时,更新
base
并重启定时器。 - 如果定时器超时,从
base
重新发送整个窗口内的数据包。 - 可以采用累积确认的方式,即收到序号为 n 的 ACK 时,表示已正确接收到序号小于等于 n 的所有数据包,此时更新
expectedSeqNum
为 n+1。
接收方
- 定义一个期望的序号
expectedSeqNum
。 - 收到数据包时,检查其序号是否等于
expectedSeqNum
,如果是,则接收并发送 ACK,同时expectedSeqNum++
,如果不是仍然发送带有expectedSeqNum
的ACK,这是为了告诉发送方目前期待的包序号为expectedSeqNum
- 如果序号不等于
expectedSeqNum
,则丢弃该数据包。 回退N步就体现在,当有接受方的ACK丢失时,发送方就重新发送[base, base + N]
的包
选择重传
思路相对简单 发送方将数据全部发送,然后打开定时器并记录接收方发送的ACK 接收方接收到数据,发送对应的ACK,否则就不发送,等待发送方的计时器结束
TCP
流程
利用了校验和、确认、序号、定时器、流水线等 技术 序号:基于字节流,报文段数据首字节的字节流 编号 确认号:已确认的最大序号加一,含义是:期望 从对方收到的下一个字节的序号 确认机制:累积确认(类似回退N步) 重传:只重传丢失或损坏的分组(类似选择重传) 快速重传:连续发送三个相同序号的ACK 定时器:针对窗口中最早未确认的分组 是回退N步和选择重传的混合体
一个包丢失的情况
sequenceDiagram participant Sender as 发送方 participant Receiver as 接收方 Sender->>Receiver: seq = 92 Sender->>Receiver: seq = 100 传输失败 Receiver-->>Sender: ack = 100 Sender->>Sender: 开启定时器 Sender->>Receiver: seq = 100, 8bytes Receiver-->>Sender: ack = 108
建立连接(三次握手)
目的:
- 使双方知道对方的存在
- 协商参数(rwnd) 握手的关键字段是SYN
- 第一次握手(C->S):
- 客户端选择一个初始序列号
x
,并发送一个SYN(Synchronize)报文给服务器。 SYN=1,seq=x
- 客户端选择一个初始序列号
- 第二次握手(S->C):
- 服务器收到SYN报文后,选择一个初始序列号
y
,并发送一个SYN=1报文给客户端。SYN=1,ACK=1,seq=y,ack=x+1
- 服务器收到SYN报文后,选择一个初始序列号
- 第三次握手(C->S):
- 客户端收到SYN报文后,发送一个ACK=1报文给服务器,确认号
seq=y+1
,表示确认收到服务器的SYNACK报文,连接建立完成。 ACK=1,ack=y+1
- 客户端收到SYN报文后,发送一个ACK=1报文给服务器,确认号
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Client->>Server: SYN位=1, seq=x Note right of Client: 选择初始序号x,发送SYN报文 Server-->>Client: SYN位=1, seq=y
ACK位=1, ack=x+1 Note left of Server: 选择初始序号y,发送SYNACK报文,确认SYN报文 Client->>Server: ACK位=1, ack=y+1 Note right of Client: 接收报文SYNACK(x+1)
说明服务器正在运行
发送ACK以确认SYNACK Note left of Server: 接收ACK(y+1)
说明客户端还在运行
握手过程中,客户端仅仅消耗一个序号 三次握手B站视频
- 第三次握手是否多余? 如果没有第三次握手,客户端在网络不畅的情况下发送建立连接的请求,没有相应后会发起第二次请求,传输完成后,第一次请求如果被服务端接收,因为客户端已经无意建立连接,服务器发送的建立连接请求会被忽略,从而导致服务端一直挂起,产生了不必要开销
断开连接(四次挥手)
挥手的关键字段是FIN
-
第一次挥手(C-S):客户端发送一个FIN(终止)报文,序列号为
u
,表示它已经没有数据要发送了。 FIN=1, ACK=1, seq=u, ack=v -
第二次挥手(S-C):服务器收到FIN报文后,发送一个ACK报文,确认号为
u+1
,表示它收到了客户端的FIN报文。 ACK=1, ack=u+1, seq=v -
第三次挥手(S-C):服务器发送一个FIN报文,序列号为
v
,表示它也没有数据要发送了。 FIN=1, ACK=1, seq=w, ack=u+1 -
第四次挥手(C-S):客户端收到服务器的FIN报文后,发送一个ACK报文,确认号为
v+1
,表示它收到了服务器的FIN报文。此时,连接正式关闭。 ACK=1, ack=w+1 seq=u+1 第二次和第三次挥手之间,服务端可能还会传输数据,大小为w-v 第三次挥手之后,客户端需要等待一段时间(两倍的MSL (Maximum Segment Lifetime)) 防止第三次报文丢失 导致服务端无法结束连接
sequenceDiagram participant Client as 客户端 participant Server as 服务器 Client->>Server: FIN=1, ACK=1, seq=u, ack=v Note right of Client: 客户端发送FIN报文,表示没有数据要发送了 Server-->>Client: ACK=1, ack=u+1, seq=v Note left of Server: 服务器确认FIN报文 Server->>Client: FIN=1, ACK=1, seq=w, ack=u+1 Note left of Server: 服务器发送FIN报文,表示没有数据要发送了 Client-->>Server: ACK=1, ack=w+1 seq=u+1 Note right of Client: 客户端确认FIN报文
![[TCP练习.png]]
CLOSE-WAIT 状态有什么意义?
服务端收到客户端关闭连接的请求并确认之后,就会进入 CLOSE-WAIT 状态。此时服务端可能还有一些数据没有传输完成,因此不能立即关闭连接,而 CLOSE-WAIT 状态就是为了保证服务端在关闭连接之前将待发送的数据处理完。
TIME-WAIT 有什么意义?
TIME-WAIT 状态发生在第四次挥手,当客户端向服务端发送 ACK 确认报文后进入 TIME-WAIT 状态。
- 防⽌旧连接的数据包 如果客户端收到服务端的 FIN 报文之后立即关闭连接,但是此时服务端对应的端口并没有关闭,如果客户端在相同端口建立新的连接,可能会导致新连接收到旧连接残留的数据包,导致不可预料的异常发生。
- 保证连接正确关闭 假设客户端最后一次发送的 ACK 包在传输的时候丢失了,由于 TCP 协议的超时重传机制,服务端将重发 FIN 报文,如果客户端没有维持 TIME-WAIT 状态而直接关闭的话,当收到服务端重新发送的 FIN 包时,客户端就会使用 RST 包来响应服务端,导致服务端以为有错误发生,然而实际关闭连接过程是正常的。
流量控制
接受方希望可以控制发送方的发送速度 TCP 使用滑动窗口机制来实现流量控制
- 接收方告知发送方自己的接收窗口大小(rwnd, Receive Window)
- 发送方发送数据时,只能发送窗口内的数据
- 每收到一个确认(ACK),发送窗口就向前滑动到ACK的序号位
发送多少要取
min(rwnd, 拥塞窗口大小)
已发送未确认(没有收到对应ACK)的字节数 <= rwnd 即 LastByteSent – LastByteAcked <= rwnd 流量控制B站视频
拥塞控制
慢启动阈值(Slow-Start Threshold)当出现超时时,sst变为原始的一半 MSS (Maximum Segment Size 最大分段大小)MSS 的主要作用是限制每个 TCP 段中所包含的用户数据的大小,从而避免在网络传输过程中因为过大的数据段导致的分片(fragmentation)问题。
- 如何增加cwnd(Congestion Window 拥塞窗口)? 线性增加(拥塞避免): 每个RTT增加一个MSS 增长速度慢,但一旦发生拥塞损失小 指数增加(慢启动): 每个RTT增加一倍MSS 增长速度快,但一旦发生拥塞损失大 最好先指数增加,超过一定阈值以后线性增加
- 丢包时,如何降低cwnd? 定时器超时 说明拥塞 将cwnd降为初始值,进入慢启动(指数增长)阶段
- 收到3个冗余ACK 虽然某个分组丢失了,但有些分组被收到了,说明拥塞 不是很严重 将cwnd减半,进入拥塞避免(线性增长)阶段 ![[拥塞控制.png|500]]
吞吐量分析
因为网络原因,有效吞吐量和理想的吞吐量指之间因为有网络延迟而不同