这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记。
TCP
TCP协议主要特点
- TCP 是
面向连接的运输层协议。应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接 - 每一条 TCP 连接只能有两个
端点,每一条 TCP 连接只能是点对点的(一对一) - TCP 提供
可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达 - TCP 提供
全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据 面向字节流。TCP 中的“流”指的是流入到进程或从进程流出的字节序列
面向字节流:
"面向字节流"的含义是:虽然应用程序和 TCP 的交互式一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。TCP 并不知道所传送的字节流的含义。
TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系
因为缓存区的存在,应用程序可能是分了10块数据进行发送的,但是TCP传输过程中可能是按照4个数据块来进行发送的。这也是粘包的原因。分别从发送端和接收端的角度来看粘包问题:
- 发送端原因: 由于TCP协议本身的机制(面向连接的可靠地协议-三次握手机制)客户端与服务器会维持一个连接(Channel),数据在连接不断开的情况下,可以持续不断地将多个数据包发往服务器,但是如果发送的网络数据包太小,那么TCP会启用Nagle算法(可配置是否启用)对较小的数据包进行合并(基于此,TCP的网络延迟要UDP的高些)然后再发送(超时或者包大小足够)。那么这样的话,服务器在接收到消息(数据流)的时候就无法区分哪些数据包是客户端自己分开发送的,这样产生了粘包.
- 接收端原因: 服务器在接收到数据库后,放到缓冲区中,如果消息没有被及时从缓存区取走,下次在取数据的时候可能就会出现一次取出多个数据包的情况,造成粘包现象。
TCP 和 UDP 在发送报文时采用的方式完全不同。TCP 并不关心应用进程一次把多长的报文发送到 TCP 的缓存中,而是根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)。如果应用进程传送到 TCP 缓存的数据块太长,TCP 就可以把它划分短一些再传送。如果应用进程一次只发来一个字节,TCP 也可以等待积累有足够多的字节后再构成报文段发送出去。
TCP的连接
TCP 把连接作为最基本的抽象。TCP 的许多特性都与 TCP 是面向连接的这个基本特性有关
TCP 连接的端点叫做套接字(socket)或插口,根据 RFC 793 的定义:端口号拼接到(concatenated with) IP 地址即构成了套接字
套接字 socket = (IP 地址:端口号)
每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定
TCP 连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}
TCP 连接就是由协议软件所提供的一种抽象。TCP 连接的端口是个很抽象的套接字,即( IP地址: 端口号)。同一个 IP 地址可以有多个不同的 TCP 连接,而同一个端口号也可以出现在多个不同的 TCP 连接中。
TCP三次握手
三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息.
第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
一次TCP从连接到传输的过程:
对概念的说明:
sequence number: 表示的是我方(发送方)这边,这个packet的数据部分的第一位应该在整个数据流中所在的位置。
acknowledge number:表示的是期待的对方(接收方)的下一次sequence number是多少。
为什么需要三次握手
参考链接:zhuanlan.zhihu.com/p/38240894
三次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
1、三次握手可以防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
具体例子:已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。
2、三次握手也可以避免死锁问题。
具体例子:作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
TCP可靠传输的工作原理
理想的传输条件
理想的传输条件有以下两个特点
- 传输信道不产生差错
- 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据
实际的网络不具备以上两个理想条件。需要使用一些可靠的传输协议,当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当减低发送数据的速度。这样,不可靠的传输信道就能够实现可靠传输了
停止等待协议
全双工通信的双方既是发送方也是接收方。把传送的数据单元都称为分组。“停止等待”就是每发完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
只要超过一段时间没有收到确认,就认为刚才发送的分组丢失了,因而重传前面发送过的分组。这就叫做超时重传。要实现超时重传,就要在每发送完一个分组时设置一个超时计时器
- 发送完一个分组后,
必须暂时保留已发送的分组的副本(在发生超时重传时使用)。只有在收到相应的确认后才能清除暂时保留的分组副本 - 分组和确认分组都必须进行
编号。这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认 - 超时计时器的重传时间
应当比数据在分组传输的平均往返时间更长一些
确认丢失和确认迟到
使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信
像上述的这种可靠传输协议常称为自动重传请求 ARQ(Automatic Repeat reQuest)。重传的请求是自动进行的。接收方不需要请求发送方重传某个出错的分组。
信道利用率
停止等待协议的优点是简单,但缺点是信道利用率太低
为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输。流水线传输就是发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可使信道上一直有数据不间断地在传送。这种传输方式可以获得很高的信道利用率。
连续ARQ协议
位于发送窗口内的5个分组都可以连续发送出去,而不需要等待对方的确认。可以提高信道利用率。
接收方一般都是采用累积确认的方式。接收方不需要对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认
积累确认有优点也有缺点。有点是容易实现,即使确认丢失也不必重传。缺点是不能向发送方反映出接收方已经正确收到的所有分组的信息。
TCP报文段的首部格式
TCP 虽然是面向字节流的,但 TCP 传送的数据单元却是报文段。一个 TCP 报文段分为首部和数据两部分。TCP 报文段首部的前20个字节是固定的,后面有4n字节是根据需要而增加的选项(n是整数)。因此 TCP 首部的最小长度是20字节。
首部字段
源端口和目的端口各占2个字节,分别写入源端口号和目的端口号序号占4字节。序号范围是[0, 2^(32-1)]。序号增加到2^(32-1)后,下一个序号就又回到0。在一个 TCP 连接中传送的字节流中的每一个字节都按顺序编号确认号占4字节,是期望收到对方下一个报文段的第一个数据字节的序号数据偏移占4字节,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。这个字段实际上是指出 TCP 报文段的首部长度保留占6位,保留为今后使用,但目前应置为0
下面有6个控制位,用来说明本报文段的性质
紧急 URG(URGent)当 URG=1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不是按原先的排队顺序来传送确认 ACK(ACKnowledgment)仅当 ACK=1 时确认号字段才有效。当 ACK=0 时,确认号无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置1推送 PSH(Push)当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应复位 RST(ReSeT)当 RST=1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接同步 SYN(SYNnchronization)在连接建立时用来同步序号。当 SYN=1 而 ACK=0 时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使 SYN=1 和 ACK=1终止 FIN(FINis)用来释放一个连接。当 FIN=1 时,表明此报文段的发送发的数据已发送完毕,并要求释放运输连接。窗口占2字节。窗口值是[0, 2^(16-1)]之间的整数。检验和占2字节。检验和字段检验的范围包括首部和数据这两部分紧急指针占2字节。紧急指针仅在 URG=1 时才有意义,它指出本报文段中的紧急数据的字节数选项长度可变,最长可达40字节。(建立连接的时候可以用来传递最大报文段长度 MSS信息,通常是MTU-20(头部大小))
TCP可靠传输的实现
以字节为单位的滑动窗口
TCP 的滑动窗口是以字节为单位的。假定 A 收到了 B 发来的确认报文段,其中窗口是20字节,而确认号是31(这表明 B 期望收到的下一个序号是31,而序号30为止的数据已经收到了)。根据这两个数据,A 就构造出自己的发送窗口。
发送窗口标识:在没有收到 B 的确认的情况下,A 可以连续把窗口内的数据都发送出去。凡是已经发送出去的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。
发送窗口的变化
发送窗口的位置由窗口前沿和后沿的位置共同确定。发送窗口后沿的变化情况有两种,即不动(没有收到新的确认)和前移(收到了新的确认)。发送窗口后沿不可能向后移动,因为不能撤销已收到的确认
发送窗口前沿通常是不断向前移动,但也有可能不动。这对应于两种情况:
- 一是没有收到信的确认,对应通知的窗口大小也不变
- 二是收到了新的窗口但对方通知的窗口缩小了,使得发送窗口前沿正好不动
发送窗口前沿也有可能向后收缩。这发生在对方通知的窗口缩小了。但 TCP 的标准强烈不赞成这样做。因为很可能发送方在收到这个通知以前已经发生了窗口中的许多数据,现在又要收缩窗口,不让发送这些数据,这样就会产生一些错误。
要描述一个发送窗口的状态需要三个指针:P1,P2,P3。指针都指向字节的序号。这三个指针指向的几个部分的意义如下:
- 小于 P1 的是已发送并已收到确认的部分,而大于 P3 的是不允许发送的部分
- P3 - P1 = A 的发送窗口
- P2 - P1 已发送但尚未收到确认的字节数
- P3 - P2 允许发送但当前尚未发送的字节数(又称为
可用窗口或有效窗口)
B 的接收窗口大小是20。在接收窗口外面,到30号为止的数据是已经发送过确认,并且已经交付主机了。因此在 B 可以不再保留这些数据。接收窗口内的序号(31~50)是允许接收的。在上图中,B 收到了序号为32和33的数据。这些数据没有按序到达,因为序号为31的数据没有收到(也许丢失了,也许滞留在网络中的某处)。请注意,B 只能对按序收到的数据中的最高序号给出确认,因此 B 发送的确认报文段中的确认号仍然是31(即期望收到的序号),而不是32或33
现在假定 B 收到了序号为31的数据,并把序号为31~33的数据交付主机,然后 B 删除这些数据。接着把接收窗口向前移动3个序号,同时给 A 发送确认,其中窗口值仍为20,但确认号是34.这表明 B 已经收到了到序号33为止的数据。B 还收到了序号为37,38和40的数据,但这些都没有按序到达,只能先暂存在接收窗口中。A 收到 B 的确认后,就可以把发送窗口向前滑动3个序号,但指针 P2 不动。现在 A 的可用窗口增大了,可发送的序号范围是42~53
A 在继续发送完序号42~53的数据后,指针 P2 向前移动和 P3 重合。发送窗口内的序号都已用完,但还没有再收到确认。由于 A 的发送窗口已满,可用窗口已减小到零,因此必须停止发送。发送窗口内所有的数据都已正确到达 B,B 也早已发出了确认。但所有这些确认都滞留在网络中。在没有收到 B 的确认时,A 不能猜测:“或许 B 收到了吧!”为了保证可靠传输,A 只能认为 B 还没有收到这些数据。于是,A 在经过一段时间后(由超时计时器控制)就重传这部分数据,重新设置超时计时器,知道收到 B 的确认为止。如果 A 收到确认号落在发送窗口内,那么 A 就可以发送窗口继续向前滑动,并发送新的数据。
缓存和窗口
发送方维持的发送缓存和发送窗口,以及接收方维持的接收缓存和接收窗口。
发送缓存用来暂时存放:
- 发送应用程序传送给对方 TCP 准备发送的数据
- TCP 已发送出但尚未收到确认的数据
已被确认的数据应当从发送缓存中删除,因此发送缓存和发送窗口的后沿是重合的。发送应用程序必须控制写入缓存的速率,不能太快,否则发送缓存就会没有存放数据的空间
接收缓存用来暂时存放:
- 按序到达的、但尚未被接收应用程序读取的数据
- 未按序到达的数据
收到的分组被检测出有差错,则丢弃。接收应用程序来不及读取收到的数据,接收缓存最终就会被填满,使接收窗口减小到零。接收应用程序能够及时从接收缓存中读取收到的数据,接收窗口就可以增大,最大亦不能超过接收缓存的大小
要点小结:
- 虽然 A 的发送窗口是根据 B 的接收窗口设置的,但在同一时刻,A 的发送窗口并不总是和 B 的接收窗口一样大。通过网络传送窗口值需要经历一定的时间滞后,该时间并不确定的。
- 对于不按序到达的数据,TCP 通常是先临时存放在接收窗口,等字节流中所缺少的字节收到后,在
按序交付上层的应用进程。 - TCP 要求接收方必须有累积确认的功能,这样可以减少传输开销。
超时重传时间的选择
由于 TCP 的下层是互联网环境,发送的报文段可能只经过一个高速率的局域网,也可能经过多个低速率的网络,并且每个 IP 数据报所选择的路由还可能不同。如果把超时重传时间设置得太短,就会引起很多报文段的必须要的重传,使网络负荷增大。但若把超时重传时间设置的过长,则又使网络的空闲时间增大,减低了传输效率。
TCP 采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间 RTT。
由此计算加权平均往返时间 RTTs = (1 - α) x (旧的 RTTs) + α x (新的 RTT 样本)
TCP协议中,RFC 6298 推荐的 α 值为 1/8,即 0.125。同时还需要计算RTT的差值的加权平均值RTTD。
RTTD = (1 - β) x (旧的 RTTD) + β x |RTTs - 新的 RTT 样本|
β:小于1的系数,推荐值是 1/4,即 0.25。结合RTTD和RTTs可以计算出超时重传时间RTO
RTO=RTTs + 4 x RTTD
TCP 流量控制
流量控制(flow control):让发送方的发送速率不要太快,要让接收方来得及接收
cwnd:发送端窗口( congestion window )
rwnd:接收端窗口(receiver window)
利用滑动窗口机制可以很方便地在 TCP 连接上实现对发送方的流量控制。
发送方的发送窗口不能超过接收方给出的接收窗口的数值。TCP 的窗口单位是字节,不是报文段
流量控制实际上是端到端的,由接收端的应用层处理速度决定和网速无关,由接收端返回的rwnd控制。
TCP的滑动窗口是动态的,可以想象成小学常见的一个数学题,一个水池,体积V,每小时进水量V1,出水量V2。当水池满了就不允许再注入了,如果有个液压系统控制水池大小,那么就可以控制水的注入速率和量。这样的水池就类似TCP的窗口。应用根据自身的处理能力变化,通过本端TCP接收窗口大小控制来对对对端的发送窗口流量限制。
应用程序在需要(如内存不足)时,通过API通知TCP协议栈缩小TCP的接收窗口。然后TCP协议栈在下个段发送时包含新的窗口大小通知给对端,对端按通知的窗口来改变发送窗口,以此达到减缓发送速率的目的。
避免死锁:TCP 为每一个连接设有一个持续计时器(persistence timer)。只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带1字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。如果窗口仍是零,那么收到这个报文段的一方就重新设置持续计时器。如果窗口不是零,那么死锁的僵局就可以打破了。
TCP发送机制
- TCP 维持一个变量,它等于
最大报文段长度 MSS。只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去 - 由发送方的应用进程指明要求发送报文段,即 TCP 支持的
推送(push)操作 - 发送方的一个计时器期限到了,这时把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去
Nagle算法
若发送应用进程把要发送的数据逐个字节地送到 TCP 的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段。当数据达到较快而网络速率较慢时,用这样的方法可明显地减少所用的网络宽带。Nagle 算法还规定,当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段。这样可以有效提高网络的吞吐量。
TCP拥塞控制
在计算机网络中的链路容量(即宽带)、交换结点中的缓存和处理机等,都是网络资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做拥塞(congestion)
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都是一个前提,就是网络能够承受现有的网络负荷
发送端主动控制控制cwnd,TCP 进行拥塞控制的算法有四种,即慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)和快恢复(fast recovery)。
慢开始
当主机开始发送数据时,由于并不清楚网络的负荷情况,如果立即把大量数据字节注入到网络,就有可能引起网络发生拥塞。经验证明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值
cwnd:发送方的拥塞窗口,开始发送方设置 cwnd = 1
拥塞避免
让拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加1,而不是像慢开始阶段那样加倍增加。因此在拥塞避免阶段就有“加法增大” AI(Additive Increase)的特点。这表明在拥塞避免阶段,拥塞窗口 cwnd 按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多
“拥塞避免”并非完全能够避免拥塞,而是把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞
在执行慢开始算法时,发送方每收到一个队新报文段的确认 ACK,就把拥塞窗口值加倍,然后开始下一轮的传输。因此拥塞窗口 cwnd 随着传输轮次按指数规律增长。当拥塞窗口 cwnd 增长到慢开始门限值 ssthresh 时,就改成执行拥塞避免算法,拥塞窗口按线性规律增长。
ssthresh:慢开始门限,一般的,会有一个初始值,下图中为16个报文段
快重传和快恢复
如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。这时,TCP马上把拥塞窗口 cwnd 减小到1(报文段大小),并执行慢开始算法,同时把慢开始门限值ssthresh减半。这是不使用快重传的情况。
快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。
与快重传配合使用的还有快恢复算法,其过程有以下两个要点:
-
当发送方连续收到三个重复确认,就执行“乘法减小”算法,把慢开始门限ssthresh减半。这是为了预防网络发生拥塞。请注意:接下去不执行慢开始算法。
-
由于发送方现在认为网络很可能没有发生拥塞,因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
TCP断开连接
四次挥手
第一次:主机1(可以使客户端,也可以是服务器端),设置Sequence Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
第二次:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;
第三次:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;
第四次:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。
为什么需要四次挥手
TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。
TIME-WAIT等待时间
为什么 主机1 在 TIME-WAIT 状态必须等待 2MSL 的时间呢?
为了保证主机1发送的最后一个 ACK 报文段能够到达主机2。这个 ACK 报文段有可能丢失,因而使处在 LAST-ACK 状态的主机2收不到对已发送的 FIN + ACK 报文段的确认。主机2会超时重传这个 FIN + ACK 报文段,而主机1就能在 2MSL 时间内收到这个重传的 FIN + ACK 报文段。接着 主机1 重传一次确认,重新启动 2MSL 计时器。最后,主机1 和 主机2 都正常进入到 CLOSED 状态。如果 主机1 在 TIME-WAIT 状态不等待一段时间,而是在发完 ACK 报文段后立即释放连接,那么就无法收到 主机2 重传的 FIN + ACK 报文段,因而也不会再发送一次确认报文段。这样,主机2 就无法安装正常步骤进入 CLOSED 状态
保活计时器(keepalive timer)
保活计时器(keepalive timer):服务器每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是两小时。若两小时没有收到客户的数据,服务器就发送一个探测报文段,以后则每隔75秒发送一次。若一连发送10个探测报文段后仍无客户的响应,服务器就认为客户端出了故障,接着就关闭这个连接