正文
4、TCP
(1)TCP 是什么
传输控制协议 (Transmission Control Protocol, TCP) 是 可靠的、面向连接 的数据传输服务
- 可靠:能够保证数据到达目的地,且到达目的地时顺序是正确的
- 面向连接:需要先建立连接后才能传输数据,建立连接需要三次握手,释放连接需要四次挥手
TCP 和 UDP 的区别?
1、TCP 提供可靠的数据传输服务,UDP 只是尽最大努力交付
2、TCP 是面向连接的,UDP 是无连接的
3、TCP 是面向字节流的,UDP 是面向数据包的
4、TCP 首部较大(20 bytes),UDP 首部较小(8 bytes)
5、TCP 是一对一的,UDP 是一对多的
(2)TCP 数据段格式
传输层数据段是对应用层消息的封装,TCP 协议由于需要保证传输可靠,所以添加的头部字段也比较多
- source port number:发送方的端口号
- destination port number:接收方的端口号
- sequence number:序列号
- acknowledge number:确认号
- head length:头部长度
- not used:保留使用
- U:紧急控制位,若为 1,说明报文包含紧急数据,需要优先处理
- A:确认控制位,若为 1,说明确认号是有效的
- P:推送控制位,若为 1,收到报文后不放进缓存,直接传给上层
- R:复位控制位,若为 1,说明连接发生错误,需要重新建立
- S:同步控制位,用于同步序列号
- F:终止控制位,若为 1,说明数据发送完毕,要求释放连接
- receive window:接收方窗口大小
- checksum:校验和,用于检查数据是否正确
- urgent pointer:紧急指针,标识紧急数据的位置
- options:长度可变,用于添加别的信息
UDP 是 面向数据包 传输的,而 TCP 是 面向字节流 传输的,这是什么意思呢,这里给大家举一个例子
假如现在需要传输一个 500000 byte 的大文件,然后已知最大报文段长度 (MSS) 等于 1000 byte
那么 TCP 会将文件划分为一段一段的字节流进行传输,每一段字节流的大小都是 1000 byte
发送方发送的序列号就是每段字节流第一个字节的编号,接收方返回的确认号表明下一个期望收到的字节的编号
(3)可靠数据传输
TCP 采用流水线协议,但是在发送方和接收方采取的动作上,又和 GBN、SR 有一点点的不同
对于接收方而言:
如果收到一个正确的分组,并且序列号 n 在接收窗口范围内,那么就把分组放在缓存
此时检查接收窗口,如果有顺序正确的分组,那么按照顺序把分组交给上层,然后向前移动窗口
之后返回一个 ACK,带上最后一个传到上层的分组的序列号
如果收到一个正确的分组,但是序列号 n 不在窗口的范围内,或者是收到错误的分组,那就什么都不要做
对于发送方而言:
如果收到上层调用,那就发送下一个分组
如果发生超时事件,重发那个序列号最小的没有被确认的分组
如果收到三次 ACK(n),并且序列号 n 小于等于窗口始端,那就重发序列号为 n 的分组
如果收到 ACK(n),并且序列号 n 大于窗口始端,那就向前移动窗口,使得 base = n
nextSeqNum = InitialSeqNumber SendBase = InitailSeqNumber loop(forever) { switch(event) event: data received from application above create TCP segment with sequence number NextSeqNum if (timer currently not running) start timer pass segment to IP NextSeqNum = NextSeqNum + length(data) break event: timer timeout retransmit not-yet-acknowledged segment with smallest sequence number start timer break event: ACK received, with ACK field value of y if (y > snedBase) { SendBase = y if (there are currently not-yet-acknowledged segments) start timer } else { increment count of duplicate ACKs received for y if (number of duplicate ACKs received for y == 3){ resend sgment with sequence number y } } break }
(4)连接管理
TCP 是面向连接的,在传输数据前需要建立连接,在传输数据后也要释放连接
建立连接需要三个步骤,称为 三次握手,具体的过程如下:
客户端发送 SYN,指明客户端的初始序列号,进入 SYN-SENT 状态
- 服务端收到 SYN,返回 SYN + ACK,表明已收到报文同时指明服务端的初始序列号,进入 SYN-RCVD 状态
- 客户端收到 SYN + ACK,发送 ACK,并且可以带上要发送的数据,进入 ESTABLISHED 状态
- 服务端收到 ACK,随即进入 ESTABLISHED 阶段,此时 TCP 连接建立完成
为什么是三次握手,而不是两次或四次?
第一次握手:客户端发送 SYN,服务端收到 SYN,此时服务端可以确认 客户端的发送能力 OK
第二次握手:服务端返回 SYN + ACK,客户端收到,此时客户端可以确认 服务端的接收和发送能力 OK
第三次握手:客户端发送 ACK,服务端收到 ACK,此时服务端可以确认 客户端的接收能力 OK
三次握手有什么作用?
第一,使双方做好数据交换的准备工作,比如准备好接收缓存和发送缓存等
第二,确定双方的初始序列号;
第三,保证双方的接受和发送能力正常
释放连接需要四个步骤,称为 四次挥手,具体的过程如下:
当客户端发送完所有数据后,给服务端发送 FIN,进入 FIN-WAIT-1 状态,说明自己已经没有数据还要发送
服务端收到 FIN,返回一个 ACK,然后进入 CLOSE-WAIT 状态
此时处于一个半关闭状态,意味着客户端不会再发送数据,但如果服务端还有数据要发送,客户端也会接收
客户端收到 ACK 之后,继续等待接收 FIN,进入 FIN-WAIT-2 状态,此时还能接收服务端的数据
服务端发送完所有数据后,给客户端发送 FIN,进入 LAST-ACK 状态,等待客户端最后的确认
客户端收到 FIN,返回一个 ACK,然后进入 TIME-WAIT 状态
此时客户端并不会真正关闭连接,必须经过 2MSL 时间之后,才会关闭连接,进入 CLOSED 状态
服务端收到 ACK 之后,立即关闭连接,进入 CLOSED 状态
为什么连接的时候是三次握手,而关闭的时候却是四次挥手?
因为在第二次握手时,服务端能够把 SYN + ACK 一起发送过去,其中 SYN 用于同步, ACK 用于应答
但在四次挥手过程中,服务端收到 FIN 之后,可能还有其它数据还要发送,所以只能先回复一个 ACK
等到服务端也发送完数据之后,才会再发送一个 FIN
客户端为什么要经过 TIME-WAIT 阶段才会进入 CLOSED 阶段?
因为客户端要保证服务端能够收到 ACK,如果服务端没有收到 ACK,服务端会重发 FIN
客户端再次收到 FIN 后,就知道之前的 ACK 已经丢失,然后重发一个 ACK,继续等待 2MSL 时间
如果在 2MSL 时间内,客户端没有再收到 FIN,它就知道服务端已经收到 ACK,然后就可以关闭连接
(5)流量控制
接收方有接收缓存,在接收数据时,网络层会往缓存中放入数据,应用层会从缓存中拿走数据
由于应用层的速度相对较慢,所以为了不使缓存溢出,我们要控制发送方的发送速率,这就是流量控制
接收方会把接收窗口的大小放在数据段发给发送方,发送方根据接收窗口的大小控制发送的速率
(6)拥塞控制
如果网络上有太多的数据,很可能会导致丢失和延迟,所以我们要控制发送方的发送速率,这就是拥塞控制
首先一个问题,发送方怎么感知到网络拥塞呢?实际上发送方可以通过超时事件和收到三次重复 ACK 进行判断
如果发生网络拥塞又应该怎么办呢?一个比较著名的解决方法就是 Reno 拥塞控制算法,整个过程如下:
- 当拥塞窗口小于阈值时,拥塞窗口指数增加
- 当拥塞窗口大于等于阈值时,拥塞窗口线性增加
- 如果收到三次重复 ACK,阈值 = 拥塞窗口 / 2,拥塞窗口 = 阈值
- 如果发生超时事件,阈值 = 拥塞窗口 / 2,拥塞窗口 = 1MSS
文章知识点与官方知识档案匹配,可进一步学习相关知识