小言_互联网的博客

【网络原理3】TCP连接管理

342人阅读  评论(0)

        TCP这种传输层协议必须是有连接的。连接管理,就是TCP当中管理如何建立连接、如何断开连接的方式。

目录

TCP建立连接的方式(三次握手)

合并两次连接之后变成"三次握手"

站在具体发送什么报文的视角,理解三次握手 

 发送报文之前

第一步:客户端主动向服务端发送(第一次握手)

第二步:服务端主动向客户端发送(第二次握手)

第三步:客户端主动向服务端发送(第三次握手)

第四步:三次握手建立连接完成之后

为什么三次握手必须是三次,不可以是四次

四次握手可以合并成三次的原因:

三次握手,为什么不可以是两次

 总结一下:三次握手的作用(两个)

TCP四次挥手

四次挥手,为什么不可以像三次握手一样合并中间两次握手

第一步:客户端主动发起FIN:

第二步:服务端主动发送ack

第三步:服务端主动发送FIN

第四步:客户端收到FIN之后,再次发送ack 

 第二、第三次握手为什么不可以合并

 四次挥手当中涉及到的两个重要的TCP状态

服务端出现大量的close_wait状态是什么原因


TCP建立连接的方式(三次握手)

通信双方需要彼此记录对方的信息,彼此之间需要"相互认同"。

下面,通过一个故事,来理解一下"三次握手"。

所谓建立连接,一定是客户端服务端之间建立连接


一天,小明去对小红表白(建立连接);

发生了以下的场景:

时间轴 小明(客户端) 小红(服务端)
t1 小红小红,你可以成为我npy吗?
t2 好啊好啊
t3 小明小明,你可以成为我npy吗?
t4 好啊好啊

       以上场景,每通话一次,相当于一次"握手"。在通话完成之后,小明与小红就正式成为NPY,也就是建立连接。

        我们都说,TCP是通过三次握手建立连接的。但是,在上述的场景当中,可以看到:出现了4次"握手",本质上也就是4次交互。但是,为什么又说是"三次"呢?


合并两次连接之后变成"三次握手"

       可以看到,在t2,t3两个时刻,小红发出了两次消息,如果把这两次消息合并成为1次。这样,4次握手,就变成了三次握手了。 


 合并之后的握手情况:

下面是具体的读取情况:

时间轴 小明 小红
t1 小红小红,你可以成为我npy吗?
t2 好啊好啊,你可以成为我的npy吗?
t3 好啊好啊

站在具体发送什么报文的视角,理解三次握手 

 发送报文之前

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
CLOSE LISTEN    

       LISTEN的含义:(相当于手机开机,信号良好)

       ①表示服务端已经准备就绪,随时可以等待客户端来建立连接了。


        ②这个状态为服务端专有的状态,含义是"监听"用于服务端监听某一个端口的状态;

    


第一步:客户端主动向服务端发送(第一次握手)

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
主动发送 SYN_SEND    syn

       同步报文段(syn标志位为1);

       客户端发送了syn报文之后,客户端进入了syn_send的状,等待服务端确认


第二步:服务端主动向客户端发送(第二次握手)

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
主动发送 SYN_RECV syn+ack

 同步报文段(syn标志位为1) 

 应答报文段(ack标志位为1)

 syn和ack都属于内核态发送的文

服务端发送之后进入SYN_RECV状态


第三步:客户端主动向服务端发送(第三次握手)

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
主动发送 进入步骤4的状态 进入步骤4的状态 ack

        应答报文段(ack标志位为1)

        此报文可以携带数据,但是前两次不可以携带数据。


第四步:三次握手建立连接完成之后

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
ESTABLISHED ESTABLISHED    

       此状态为客户端与服务端均可以有的状态,表示客户端与服务端已经经过三次握手建立好了连接。

      其中,服务端在收到最后一次ack报文之后进入ESTABLISHED状态


        读音: [ɪˈstæblɪʃt] 

 所以,综上所述,客户端与服务端之间三次握手的流程图大致为下面这样:

  


为什么三次握手必须是三次,不可以是四次

在上述的通信过程当中,每发送一次报文,就相当于封装、分用一次。

关于什么是封装、分用,也已经在这一篇文章当中提到了。

初识网络:IP、端口、网络协议、TCP-IP五层模型_革凡成圣211的博客-CSDN博客TCP/IP五层协议详解https://blog.csdn.net/weixin_56738054/article/details/128666970?spm=1001.2014.3001.5501简而言之:

封装就发送方把报文从应用层报文-->数据链路层进行的一个封装;

分用就是接收方把报文从数据链路层--->应用层的一个过程;

       而每封装、分用一次,都是需要开销的;因此,在确保发送方、接收方都可以确保双方可以接收消息的情况下,应当尽可能地减少封装、分用的次数。也就从4次握手削减为了三次;

       也就是合并了接收方回复发送方的那一次发送报文。

图解一下:三次握手:


四次握手可以合并成三次的原因:

原因1:

       三次握手的过程,是在操作系统内核当中完成的,也就是三次握手发生在内核态,应用程序无法干涉;

      也就是在第二次握手的时候,服务端的系统收到syn之后,就会立即发送ack给客户端。

      ack的发送与接收,都属于内核态的工作。

      因为握手的过程都发生在内核态,因此可以合并中间两次握手。

原因2:

      多一次握手,就会多一次分装分用的过程。每封装分用一次,都是需要比较大的开销的。


三次握手,为什么不可以是两次

如果变成了两次,就会出现下面的结果(图解)

给定下面一个场景:假设小明和小红连麦打游戏,他们之间需要彼此确认双方的话筒和耳机是否正常;

时间轴 小明 小红
t1 小红小红,你听到我说话了嘛?
t2 小明小明,我听到你说话啦

       可以看到,t1时刻,小明向小红发送了一个语音。然后小红听到了小明的语音之后(t2时刻),说明了两个事实:

 事实1:小明(发送方)语音(发送功能)正常;

 事实2:小红(接收方)耳机(接收功能)正常;

也就是说:作为发送方,它可以正常发送消息;作为接收方,它可以正常接收消息

    但是,却无法验证另外两个事实,那就是:

     事实3:小红(接收方)语音(发送功能)是否正常;

     事实4:小明(发送方)耳机(接收功能)是否正常;


 总结一下:三次握手的作用(两个)

  作用1:确保了发送方与接收方通信上面的彼此认同;

  作用2:验证了发送方与接收方的发送和接收能力是否正常;

需要注意的是:

  TCP的可靠性和有无连接没有关系

  可靠性是依靠确认应答机制(ack)+超时重传机制来保证的。

  而建立连接是依靠三次握手机制来完成发送方接收方之间的自检。 


TCP四次挥手

三次握手,是建立连接的过程。四次挥手,是断开连接的过程。

经过了四次挥手之后,客户端与服务端之间就断开连接了。

下面,通过一个场景,模拟四次挥手的过程:

假设小明想跟小红提出分手:

时间轴 小明(客户端) 小红(服务端)
t1 小红小红,我们分手吧
t2 好啊好啊
t3 小明,我们分手吧
t4 好啊好啊

       经历了以上的四次挥手之后,小明和小红就"成功分手了",也就相当于客户端与服务端主动断开连接了。


四次挥手,为什么不可以像三次握手一样合并中间两次握手

下面,站在具体发送报文的角度,理解一下四次挥手:

首先,需要了解一个前提条件:

当报文段的ack标志位为1的时候,这个报文的发送和接收都工作在内核态;

当报文段的FIN标志位为1的时候,这个报文段的发送和接收都工作在用户态;

在发起四次挥手之前,客户端和服务端都在建立连接时候的状态(ESTABLISHED) 

第一步:客户端主动发起FIN:

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
主动发送 FIN_WAIT1 FIN

①发送报文的FIN标志位为1

FIN报文段的发送与接收,都发生在用户态

③客户端发送了FIN之后进入FIN_WAIT1状态


第二步:服务端主动发送ack

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
主动发送 CLOSE_WAIT ack

①发送报文的ack标志位为1。

②ack报文段的发送发生在内核态

③服务端发送了第一次ack之后之后进入了CLOSE_WAIT状态


第三步:服务端主动发送FIN

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
主动发送 LAST_ACK FIN

①发送报文的FIN标志位为1

FIN报文段的发送与接收,都发生在用户态

③服务端发送了FIN之后,进入了LAST_ACK状态


第四步:客户端收到FIN之后,再次发送ack 

客户端 客户端状态 服务端 服务端状态 报文类型 备注(其他)
主动发送 TIME_WAIT ack

客户端发送的ack标志位为1。

发送的过程发生在内核态。


客户端发送了最后一次ack之后,自身进入了TIME_WAIT状态

ps :经过了第四步之后,客户端进入了TIME_WAIT状态,服务端在收到了ack之后,立刻进入了close状态。客户端在TIME_WAIT状态持续2MSL之后,也进入了TIME_WAIT状态。


 第二、第三次握手为什么不可以合并

       FIN的发起,不是由内核控制的,而是由应用程序发起的。当调用socket的close方法(或者进程退出)才会触发FIN。

       ACK则是由内核控制的,是在收到客户端发送的FIN之后,立即返回ACK。

      由于FIN和ACK一个工作在用户态,另外一个工作在内核态,因此不可以合并。

       但是,在特殊情况下面,也有可能合并。

       回到这一篇文章当中,实现一个简单的TCP。
(1条消息) 实现一个TCP客户端——服务端协议_革凡成圣211的博客-CSDN博客_tcp客户端实现https://blog.csdn.net/weixin_56738054/article/details/128750183?spm=1001.2014.3001.5501      

挥手次数 发起方 发送报文类型 说明
1 客户端 FIN         服务端的 scanner.hasNext()读取到的值为false,因为内核收到了客户端发送的FIN数据报。(第一次挥手)
2

服务端

ack

        在读取到scanner.hasNext()的值为false的时候,立即返回ack报文。

        步骤2在内核当中完成

3

服务端

FIN         应用程序finally代码块当中调用close方法,相当于发送FIN给客户端
4 客户端 ack         客户端在收到了步骤3发送的FIN之后,立刻在内核当中发送ack给服务端

        关于第二次挥手和第三次挥手,如果它们之间间隔的时间比较短,那么救有可能被合并成为一次。


 图解一下:客户端与服务端的发送与接收过程:下图来源于《小林coding》

  


 四次挥手当中涉及到的两个重要的TCP状态

状态的名称 状态发生的场景(假定是客户端主动断开连接,服务端被客户端断开连接) 说明 出现在哪一方
CLOSE_WAIT

如果客户端TCP主动断开服务端TCP连接,那么服务端TCP的状态就是CLOSE_WAIT,其实就是等待关闭

等待关闭:(等待调用close方法关闭连接) 被断开连接的一方
TIME_WAIT

       四次挥手结束之后,客户端进入的状态;

       此时,这里的TIME_WAIT要保持当前的TCP连接状态不要立即释放,原因:

       最后一个ack刚刚发出去的时候,防止丢失的情况。

       等待一段时间之后,如果接收方(服务端)没有收到重传的FIN。

       那么就会再由服务端发送一次FIN;         

        TIME_WAIT就是为了服务端重新发送一次ack而设定的。


       TIMEWAIT最大时间:2MSL,也就是如果服务端隔了2MSL没有发送给客户端,那么就会由服务端再次发送一次FIN

       

     出现在主动断开连接的一方;

服务端出现大量的close_wait状态是什么原因

说明服务端的程序没有调用 close 函数关闭连接,也就是说,服务端没有发送FIN报文段。


转载:https://blog.csdn.net/weixin_56738054/article/details/128961091
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场