终于总结了TCP(有点长,耐心看哦)


一提到TCP,几乎人人脑子里都是可靠、有连接、面向字节流,在提到什么超时重传、滑动窗口、流量控制等又觉得哇好难呀,其实这个内在是有一定的因果关系的,它的可靠性是由 确认应答、超时重传、建立连接来保证的,性能是由滑动窗口、延迟应答等实现的,然后就带出连拥塞控制和面向字节流等特性。
在这里插入图片描述
接下来详解TCP,先从认识它的协议格式开始

一、TCP协议格式

在这里插入图片描述
一个一个看
1、源/目的端口号:都是16位,表示从哪儿来到哪儿去(进程)
2、序号:32位,这里面的序号跟确认应答机制有关,等会详细说明。
3、TCP报头长度: 4位,表示该TCP头部有多少个32位bit(有多少个4字节),所以TCP头部最大长度是15 * 4 = 60。
4、6位标志位:
URG: 紧急指针是否有效
ACK: 确认号是否有效
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段
SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段
FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段
5、窗口大小:16位(跟滑动窗口机制有关)
6、校验和:16位, 发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也包含TCP数据部分.
7、16位紧急指针: 标识哪部分数据是紧急数据;

二、确认应答

在这里插入图片描述
你打电话给我,你得听到我的回应才是真的联系上我了。就像上图显示的这样,A向B发了一批数据,B收到了就会给A一个回应,然后这个序列就会加1,下次A就是从1001开始发的。TCP会对每个数据编号,每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.

三、 超时重传

B方未收到A的数据

两种情况需要重传(就像你给你男朋友发了个消息,两种情况下你都收不到回应,一是你发的消息他没收到,二是,他回你消息了,但你没收到他的回复)

在这里插入图片描述
A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B;如果A在一个特定时间隔内没有收到B发来的确认应答,就会进行重发,但是, 主机A未收到B发来的确认应答,也可能是因为ACK丢失了

A方未收到B的应答

在这里插入图片描述
因此主机B会收到很多重复数据. 那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉. 这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.

如何确定超时时间?

这个时间确实不好控制,谁都想等的越短越好,但过短会频繁发送重复的包,过长会影响重传效率,TCP就比较聪明了,它在实际中是动态计算这个时间的。Linux、Windows中,超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍,如果重发一次之后, 仍然得不到应答, 等待 2500ms 后再进行重传.如果仍然得不到应答, 等待 4500ms 进行重传. 依次类推, 以指数形式递增.累计到一定的重传次数, TCP认为网络或者对端主机出现异常,强制关闭连接。

四、 连接管理

这里就到面试爱问的三次握手四次挥手了,基本意思都能讲明白,一问状态转移和序列变化就翻车,(本菇凉亲测)

三次握手

核心思想就是让我知道你已经知道了。
在这里插入图片描述
1、建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;
2、服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
3、客户端收到服务器的SYN+ACK包,向服务器发送确认ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手,这时才真正的建立上了连接。

四次挥手

在这里插入图片描述
1、客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2、服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3、客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4、服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

四次挥手,搞清楚两个状态,TIME_WAIT(1、防止最后一个ACK对方没有收到,2、刚刚回收的五元组,保留一段时间在分配)和CLOSE_WAIT

先扯一张TCP的状态转换图
在这里插入图片描述

TIME_WAIT的时间是2MSL?

MSL:TCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的),同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN. 这时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重LAST_ACK);

CLOSE_WAIT

一般而言,对于服务器上出现大量的 CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭socket,导致四次挥手没有正确完成,此时应该加上对应的close

五、流量控制和拥塞控制

滑动窗口为了不做无用功,根据对方的接收能力来调节发送的大小。TCP中采用滑动窗口来进行传输控制。
滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据。发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。当滑动窗口为0时,发送方一般不能再发送数据报,但有两种情况除外,
1、可以发送紧急数据,例如,允许用户终止在远端机上的运行进程。
2、另一种情况是发送方可以发送一个1字节的数据报来通知接收方重新声明它希望接收的下一字节及发送方的滑动窗口大小
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.

因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control)
接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端; 窗口大小字段越大, 说明网络的吞吐量越高;
接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度;
如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数 据段, 使接收端把窗口大小告诉发送端.窗口越大, 则网络的吞吐率就越高。但是!窗口不能无限大,发送方发的太快,接收方可能处理不过来:

拥塞控制:

解决网络堵塞:掌握慢启动和拥塞避免算法

TCP引入慢启动机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据。慢启动的思想是:TCP 模块刚开始发送数据并不知道网络的实际情况,需要用一种试探的方式平滑的增加 CWND 的大小。
拥塞避免算法使得 CWND 按照线性方式增加,从而减缓其扩大。
慢启动阈值 (ssthresh) 会变成原来的一半, 同时拥塞窗口置回1。

两个算法的实际应用:假设TCP拥塞控制算法中,慢开始的阈值为10,当拥塞窗口上升到16时,发送端检测出超时,TCP重新启用慢开始和拥塞避免。请计算第1次到第15次传输过程中拥塞窗口的值。

TCP的窗口初始值从1开始,启用慢开始算法,每一次窗口的值增长2倍。
第1次,拥塞窗口值为2;
第2次,拥塞窗口值为4;
第3次,拥塞窗口值为8;
第4次,拥塞窗口若是增长2倍,将超过阈值16,此时启用拥塞避免算法,拥塞窗口值为10,每一次窗口的值增长1;
第5次,拥塞窗口值为11;
第6次,拥塞窗口值为12;
第7次,拥塞窗口值为13;
第8次,拥塞窗口值为14;
第9次,拥塞窗口值为15;
第10次,拥塞窗口值为16,发送端检测出超时,将重启慢开始算法,并将阈值设置为8。
第11次,拥塞窗口值为1;
第12次,拥塞窗口值为2;
第13次,拥塞窗口值为4;
第14次,拥塞窗口值为8,此时达到阈值,启用拥塞避免算法;
  第15次,拥塞窗口值为9。

六、延时应答和捎带应答

延时应答解释:

比如你正在写作业,答案已经思考出来了,这时你老妈让你去买盐,如果你立马去,等回来思考的早忘了,要是你延迟一会,把答案先写下来再去买盐,就节省下来了再次思考的时间。
放到TCP中一样的道理
如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小.
假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;一定要记得,

窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;
那么所有的包都可以延迟应答么? 肯定也不是;
数量限制: 每隔N个包就应答一次;
时间限制: 超过最大延迟时间就应答一次;
具体的数量和超时时间, 依操作系统不同也有差异; 一般N取2, 超时时间取200ms;

捎带应答解释:

你妈让你买盐你爸让你买烟,这不顺带就一起买了,其实就是捎带应答

接收端需要对每个接收到的 TCP 分组进行确认,也就是发送 ACK 报文,但是 ACK 报文本身是不带数据的分段,如果一直这样发送大量的 ACK 报文,就会消耗大量的带宽。之所以会这样,是因为 TCP 报文、IP 报文固有的消息头是不可或缺的,比如两端的地址、端口号、时间戳、序列号等信息。

七、TCP异常情况

视频一半突然断电断网了?电脑突然死机关机了?开着的那些应用你可没关丫,分三种情况分析
1、进程终止: 进程终止会释放文件描述符, 仍然可以发送FIN. 和正常关闭没有什么区别。
2、机器重启: 和进程终止的情况相同.
3、机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行reset. 即使没有写入操作, TCP自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果对方不在, 也会把连接释放。另外, 应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ, 在QQ断线之后, 也会定期尝试重新连接.

猜你喜欢

转载自blog.csdn.net/chris__x/article/details/106653014
今日推荐