TCP
Contents
TCP 的特点
- 面向连接
- 可靠服务
- 面向字节流
面向连接
- 连接就是一对一,当双方都确认对方是谁时,连接就建立起来了,
源IP
+源端口号
+目标IP
+目标端口号
就可以唯一确定一个连接
三次握手建立连接
- 三次握手流程
- 客户端发送一个SYN包,进入 SYN_SENT 状态;
- 服务器收到 syn 包,向服务器发送 syn+ack 包,服务器进入 SYN_RECV 状态;
- 客户端接收到 syn+ack 包,向服务器发送 ack 包。
- 为什么要三次握手?两次可不可以?
- 如果客户端发送的 syn 包在网络中绕了很久才到达服务器,但是此时客户端早已经重传 syn 包并且建立连接传输数据关闭连接了。此时服务器接收到迟到的 syn 包,就直接建立连接,但是客户端并不会接受,所以此时只有服务器建立了连接,一直等待客户端,造成了资源的浪费。
四次挥手断开连接
- 四次挥手流程
- 客户端发送 fin 包,用来关闭客户端到服务器的数据传送,并进入FIN_WAIT_1 状态
- 服务器收到 fin 包,返回一个 ack 包,客户端收到 ack 之后进入FIN_WAIT_2 状态
- 服务器向客户端发送 fin 包,用于关闭服务器到客户端的数据传送
- 客户端收到服务器的 fin 包之后,回发 ack 包,进入 TIME_WAIT 状态,等待 2MSL(Maximum Segment Lifetime) 的时间。
- 为什么最后要等待 2MSL?
- 为了防止 ack 丢失,服务器重新发送 fin 包的情况。
- 为什么要四次握手?
- 因为当服务器端收到客户端的 syn 连接请求报文之后,可以直接发送 syn+ack 报文。但是关闭连接时,当服务器接收到 fin 报文时,很可能并不能立即关闭服务器到客户端的数据传输,因为服务器的数据还没有传输完,需要等到服务器端的数据传输完之后才能发送 fin 报文。
可靠传输
- TCP主要通过
超时重传
、确认
、传输序号
(解决失序和重复问题)、校验和
等手段来实现可靠的传输。
ARQ
- ARQ协议,即
自动重传请求
(Automatic Repeat-reQuest),是OSI模型中数据链路层和传输层的错误纠正协议之一。 - 它通过使用
确认
和超时
这两个机制,在不可靠服务的基础上实现可靠的信息传输。 - ARQ包括
停止等待ARQ协议
和连续ARQ协议
;- 停止等待ARQ协议:每次发送都需要等待确认再进行下一次发送;
- 无差错情况:A发送M1并等待B确认,B确认后A继续发送M2
- A发送数据包出错或丢失:超时重传【A需要保存副本以便重传;超时时间应该略长于RTT(数据包往返时间)超时时间以及重传次数会在下面具体讲】
- 确认丢失:A会重复发送M1,B收到后根据序号可知该数据包已经收到过了,会直接丢弃该数据包,并再次向A发送确认
- 确认延迟:即A会收到重复确认,此时A什么都不做(根据序号可知,已经确认过)
- 连续ARQ
- 提高信道利用率,连续发送多个数据包,不需要每次都等待确认之后再发送
- 接收方一般采取累积确认;
- 优点:不必对收到的每个分组都进行确认,而是对按序到达的最后一个分组进行确认即可,这表明所有序列号小于等于该分组序列号的分组都已经收到;
- 缺点:不能正确的反映收到的分组【?是否为每个数据包都设置一个计时器?】,比如发送方发送了前5个分组,而中间的第3个分组丢失了【如何判断第三个丢了?超时?】,这时候接收方只能对前2个发出确认。而不知道后面3个分组的下落,因此只能把后面的3个分组都重传一次【需要吗?如果是快重传呢?快重传不是这意思,会讲到】,这种机制叫Go-back-N(回退N),表示需要再退回来重传已发送过的N个分组。
- 连续ARQ协议通常是结合滑动窗口协议来使用
- 停止等待ARQ协议:每次发送都需要等待确认再进行下一次发送;
滑动窗口协议
- 滑动窗口使得连续ARQ协议可以连续发送多个分组而不用等待
- 以字节为单位;
- 滑动窗口协议涉及到三个窗口
- 发送窗口(swnd):在发送方,窗口大小表示可以连续发送的数据量,由接收方接收窗口和拥塞窗口决定(两者更小的那一个)
- 接收窗口(rwnd):在接收方维护,可以表示接收者的接收能力;
- 拥塞窗口(cwnd):主要用于拥塞控制;拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。
- 滑动窗口有两个作用
- 流量控制:防止发送方过载接收方
- 拥塞控制:防止发送方过载网络,采用控制拥塞窗口大小的方式来进行拥塞控制
- 流量控制
- 接收方返回的 ACK 中会包含自己的接收窗口的大小,从而控制发送方的数据发送
- 零窗口和坚持定时器(TCP Persist Timer)
- 零窗口:当接收方缓存满时,就会告诉发送方接收窗口为0;发送方接收到后停止发送,直至收到非零通告;【但是如果接收方的非零通告丢失了呢?(因为非零通告是以ACK的方式发送的,发送方并不会对ACK进行确认,所以接收方不会有超时重传非零通告的机制,此时就陷入了死锁)】
- 坚持计时器:用于解决zero window可能造成的死锁,当发送方收到zero window之后,就启动一个计时器,计时器超时之后发送方会发送窗口探查报文(window probe)询问接收方窗口是否扩大;
- 拥塞控制
- 慢启动:
- 指的是拥塞窗口初始化为较小的值,并由小到大增加拥塞窗口数值
- 一般开始时会把cwnd设为MSS(也就是一个报文大小)
- 慢启动并不意味着拥塞窗口大小增长速度满,每收到一个数据报确认都会将窗口增加MSS;每经过一个传输轮次且报文都收到确认时,拥塞窗口大小加倍(指数增长);
- 当cwnd大小超过慢开始门限(ssthresh)时,慢开始算法转为拥塞避免算法;
- 拥塞避免
- 让cwnd缓慢增大,每经过一个传输轮次增加1个报文大小,而不是加倍;(线性增长)
- 无论在拥塞避免阶段还是慢启动阶段,一旦出现拥塞(丢包,吞吐率下降),就要把慢开始门限设为cwnd的一半(不能小于2个报文大小),把cwnd设为1个报文大小,并进入慢启动阶段;
- 快重传
- 当一个报文丢失,发送方迟迟收不到确认,超时之后就会重传该报文,但超时机制增加了端到端的时延;
- TCP采用的是累积确认机制,当接收方接收到比期望序号大的报文段时,便会重复发送最近一次的报文确认,重复发送的ACK叫做冗余ACK;
- 如果在超时之前收到了三个重复的冗余ACK(总共收到了4个ACK),接收端便知道哪个报文丢失了,于是立即重发该报文,而不必等待超时;
- 快恢复
- 与快重传配合
- 当连续收到三个重复确认并不能判断该报文是因为网络拥塞丢失还是因为其他原因,所以并不执行慢启动算法,而是将慢开始门限(ssthresh)设为当前cwnd的一半,并将cwnd设为新的ssthresh(也就是将cwnd减半),然后开始拥塞避免算法(cwnd线性增长);
- 因为超时造成重传
- 表明网络大概率拥塞,所以将ssthresh设为当前cwnd的一半,将cwnd设为1,并开始慢启动算法;
- 所以慢启动算法只会在TCP连接建立,或超时重传时采用
- 慢启动:
超时重传
- 超时重传等待时长
- 第一次发送后设置的超时时间是1.5秒,此后该时间在每次重传时增加1倍并直至64秒;
- 重传几次
- 一共重传12次(1.5,3,6,12,24,48 和多个64),大概需要9分钟才会放弃重传;
面向字节流
- 字节流服务指的是TCP不需要在字节流中间插入标记来标识TCP数据包的边界。
Author 段新朋
LastMod 2020-06-28