1.简介
传输控制协议,是一种面向连接的、可靠的、基于IP的传输层协议。
TCP工作于
传输层
,IP在网络层
,ARP在数据链路层
- 源端口和目的端口: 各占两个字节,这两个值加上IP首部中的源端IP地址和目的端IP地址唯一确定一个TCP连接。
一个IP一个端口也称为Socket
。 - seq序号: 占4个字节,是本报文段发送的数据项目组的
第一个字节
的序号。 - ack确认号: 占4个字节,是期望对方下一个报文端的第一个数据字节序号,也就是期望收到的下一个报文段的首部中的序号;确认序号应该是上次已成功收到数据字节序号+1,且只有ACK标志位1时,确认序号才有效。
TCP传送的数据流中,每个字节都有一个序号,序号是32bit的无符号数,到达 a 32 − 1 a^{32}-1 a32−1后从0开始
- 数据偏移: 4bit,表示数据开始的地方离TCP段的起始出有多远。实际上就是
TCP段首部的长度
。 - 保留字段: 占4bit,为TCP将来的发展预留空间,且
必须全部为0
. - 标志位字段:
- URG:为1时,表此报文应尽快送达,而不要按照本来的列队次序传送,与紧急指针字段共同应用。
- ACK:只有ACK=1时,确认字段序号才有效。
- PSH:当PSH=1时,接受方应该尽快将本报文立即传送给其应用层。
- RST:当RST=1时,表示出现连接错误,必须释放连接然后再重建传送连接。
- SYN:当SYN=1时,表示请求建立一个连接,携带SYN标志的TCP报文段为同步报文段;只有
前两次握手中SYN才为1
。 - FIN:发送端完成发送任务。
- 窗口:
- TCP通过滑动窗口的概念来进行
流量控制
,协调通信双方的工作节调,保证数据不丢失。 - 滑动窗口可以理解为接收端所能提供的
缓冲区大小
,TCP利用一个滑动窗口来告诉发送端对他发送的数据能提供多大的缓冲区。 - 窗口大小为字节数起始于
确认号字段指明的值
,此值为接收端期望接收的字节,大小为16bit字段,因此最大为65535
字节。
- TCP通过滑动窗口的概念来进行
- 检验和: 用于确认传输的数据是否有损坏。发送端基于数据内容校验生成一个值,接收端根据接收的数据检验生成一个值,
两个值必须相同才能证明数据是有效的
。如果两个值不同,则丢掉这个数据包。CheckSum是根据伪头+TCP头+TCP数据三部分进行计算的
- 紧急指针:
- 只有当URG标志置为1时紧急指针才有效。
- 是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节序号。
- 当所有紧急数据处理完后,TCP就会告诉应用程序回复正常操作。
- 即使当前窗口大小为0,也可以发送紧急数据,因为紧急数据无需缓冲。
- 可选字段: 长度不定,长度必须为
32bit的整数倍
。
2.TCP连接
2.1.建立TCP连接(三次握手)
信息对等和防止超时。
- 信息对等:自己发送报文的能力、自己接受报文的能力、对方发送报文的能力、对方接受报文的能力
- 第一次握手:Client将标志位
SYN置为1
(表示要发起一个连接),随机产生一个值seq=J
,并将该数据包发送给Server,Client进入SYN_SENT
状态,等待Server确认。 - 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位
SYN和ACK都置为1
,ack=J+1
,随机产生一个值seq=K
,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD
状态。 - 第三次握手:Client收到确认后,检查
ack是否为J+1
,ACK是否为1
,如果正确则将标志位ACK置为1,ack=K+1
,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1
,如果正确则连接建立成功,Client和Server进入ESTABLISHED
状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
2.2.断开连接(四次挥手)
- Client发送关闭数据包将
FIN设为1
,假设序列号为u
,发送关闭数据包后此时client处理FIN-WAIT-1
状态。server收到关闭连接请求后通知应用程序处理完剩下的数据。 - server响应client的关闭连接请求,将
ACK设为1
,seq为v
,ack为u+1
,随后server处于close_wait
状态。client收到应答后处于FIN-WAIT-2
状态,继续等待server的FIN数据包。 - server处理好现场后主动向client发送数据包,并将
FIN和ACK标志设置为1
,seq为w
,ack为u+1
,随后处于TIME-WAIT
状态等待client的应答。 - client收到
FIN数据包
后,随后发送ACK数据包
,seq为u+1
,ack为w+1
,此时client处理TIME-WAIT
的状态。server收到ACK响应包后进行closed
状态,连接正常关闭。client在TIME-WAIT
状态等待2msl后,也进入closed
状态,连接关闭。
2msl(2 maximum segment life time),即两个最大的报文段寿命:
- 保证客户端发送的最后一个Ack报文能到达服务器,这个报文可能丢失导致处于LAST-ACK的服务器接收不到,此时服务器会重新发送FIN+ACK报文,而2msl时间内客户端就会收到这个报文,接着重传一次ACK报文,重新启动2msl计时器,直到客户端和服务端都进入closed状态。
- 防止已失效的连接请求报文出现本连接中。和上面三次捂手是一个道理的。经过2个msl是本次连接产生的所有报文段都消失在网络中,使下一个连接不会出现这种旧的连接报文。
3.TCP可靠传输的实现
TCP发送的报文是交付给网络层的,而网络层不会保证报文不会出差错的送达,所以TCP必须采取措施使得通信可靠。TCP为了保证可靠的传输,设计了以下几种机制:
3.1.重传机制
在发送某一个数据以后开启一个计时器,在一定时间内如没得到发送的数据报的ack报文,那么久重新发送数据,直到发送成功为止。
3.2. 流量控制(滑动窗口协议)
点对点通信流量控制,也是通过接收方来控制流量的方式。
TCP通信用滑动窗口来提高通信效率,通信双方都会操作系统的缓冲区维护一个窗口
。放放可以发送一组数据出去而不需要等待接收方的应答,接收方可以采用累计确认。如此窗口定的太大,接收方接不过来导致一直重传,所以流量控制就是让发送方发送的速率不要太快。滑动窗口就是接收数据端的窗口大小,用来告诉发送端接收端的缓冲大小,以此控制发送端发送数据的大小,从而达到流量控制的目的。
rwnd(window size):接受窗口,单位是字节,用于流量控制。
3.3. TCP拥塞控制
是针对全局网络的,也是通过发送方来控制流量的方式
-
拥塞窗口: 发送方维持一个叫
拥塞窗口cmnd的状态变量
1。拥塞窗口的大小取决于网络的拥塞程度并且动态变化。原则是网络未出现拥塞,拥塞窗口就大一些,出现网络拥塞则小一些,以减少注入到网络中的分组数
。cwnd初始化为1mss,之后没收到一个ack,cwnd成指数增长一次。
-
TCP拥塞控制的方法: 慢开始slow-start,拥塞避免congestion avoidance,快重传fast retransmission,快恢复fast recovery
-
慢开始
TCP在完成连接的三次握手之后慢慢开始传数据,并不是一开始项网络通道中发送大量的数据,如不清楚网络的符合情况立即把大量的数据字节注入网络,可能会引起网络拥塞。因此现在的TCP协议规定了新建立的连接不能一开始就发送大尺寸的数据包,而只能从一个小尺寸的包开始发送。在发送和接收的过程中去计算对方的接收速度,来逐步增加每次发送的数据量。
(最后到达一个稳定的值,进入高速传输阶段)即有小到大的发送数据。慢启动阙值(ssthresh):用来限制cwnd的指数激增,一般大小为65535字节。
cwnd < ssthresh,使用慢开始算法
cwnd > ssthresh,使用拥塞避免算法
cwnd = ssthresh,以上两者皆可用 -
拥塞避免
当cwnd>=ssthresh时,cwnd的值不在指数上升,开始加法增加。此时当窗口中的所有报文端都被确认时,cwnd的大小加1,cwnd的值就会随着RTT开始线性增加
,以此避免增长过快导致网络拥塞,慢慢的增加和调整到网络的最佳值。无论是慢开始算法还是拥塞避免算法,只要是发送方判断网络出现拥塞,就要吧
ssthresh设置为当时发送窗口值的一半,然后cwnd重新设置为1,执行慢开始算法
。判断网络拥塞的方法:
- RTO超时重传
- 快速重传
-
快速重传
必要性: TCP要保证所有的数据包都可以到达,所以必需有重传机制。- 超时重传机制: 不用ack死等③,当发送方发现收不到③的ack超时后会重传③,也有可能导致④和⑤的重传。如:发送端发了①②③④⑤五个包,接受端收到了①②,于是ack③,然后收到④。
- 快速重传机制: 以上问题TCP引入一种叫做Fast retransmit的算法。
不以时间驱动而以数据驱动重传
。如包没有连续到达,就ack最后那个可能丢了的包,如发送方连续收到了3次相同的ack就重传。
-
快恢复
原理: 当接收方发送了三个重复确认之后,发送方知道有报文丢失了,发送方不启动慢开始,而是执行快速恢复算法,此时发送方调整ssthresh为一半,同时设置拥塞窗口为最新的ssthresh值,并开始执行拥塞避免算法。
-
取拥塞窗口与滑动窗口的最小值作为发送的上限。 ↩︎