• TCP三次握手和四次挥手


    TCP报文格式

     TCP报文格式图:

     

      上图中有几个字段需要重点介绍下:

      (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

      (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

      (3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:

      (A)URG:紧急指针(urgent pointer)有效。

      (B)ACK:确认序号有效。

      (C)PSH:接收方应该尽快将这个报文交给应用层。

      (D)RST:重置连接。

      (E)SYN:发起一个新连接。

      (F)FIN:释放一个连接。

     需要注意的是:

      (A)不要将确认序号Ack与标志位中的ACK搞混了。

      (B)确认方Ack=发起方Req+1,两端配对。 

    TCP三次握手

    TCP(Transmission Control Protocol) 传输控制协议

    TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接

    位码即tcp标志位,有6种标示:

    1)SYN(synchronous建立联机)

    2)ACK(acknowledgement 确认)

    3)PSH(push传送)

    4)FIN(finish结束)

    5)RST(reset重置)

    6)URG(urgent紧急)

    Sequence number(顺序号码)

    Acknowledge number(确认号码) 

    establish  建立,创建

      所谓三次握手(Three-Way Handshake)即建立TCP连接,是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:



     

      (1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。

      (2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack (number )=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。

      (3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

      SYN攻击:

      在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:

      #netstat -nap | grep SYN_RECV

    容易理解的小故事

    网络帝国的崛起

    随着时间的流逝,计算机帝国的子民耐不住寂寞,他们好想去外面的世界看看,去其他的计算机家中串串门,他们经常抱怨,为什么那些官员可以互相聊天,而我们只能自己对自己说话.

    这些抱怨传到了计算机国王的耳中,国王也很头痛啊,他也想让子民相互沟通,畅聊无阻,可是不同计算机运行着不同的操作系统,他们在表达同一种信息的时候采用的方式千差万别,很难统一啊,官员们也是费了好大劲才把那么几个操作系统的通信搞定,更何谈万千子民了.

    这一次,国王召开会议与大臣一起讨论这个问题,最终一致认为成立网络专研小组,专门研究此问题

    TCP/IP 家族的诞生

    成立专家组之后,专家立即开始讨论如何使不同计算机建立通信,通过大量的考察不同的操作系统,专家们历经千辛万苦最终制定了统一标准——TCP/IP 协议族(注意:TCP/IP不是一个协议,而是一系列协议的总和),这个家族里包含了许多协议,比如常见的TCP协议,UDP协议

    一次奇异的聊天

    专家组把协议给国王看了看,国王非常高兴,马上派人把TCP/IP协议族中的所有协议分发给万千子民并给每一位子民拉了一根网线,子民们收到也非常高兴,各自研究其协议了

    上官天宇和司马剑就是其中两位(下称上官和司马),数天后,在得知上官的地址(对应IP和端口)后,司马决定用可靠传输的TCP和上官进行通信,因为他不想在第一次聊条中漏掉任何文字

    可是这个TCP有几个比较讨厌的就是聊天之前要做很多准备工作,有两步(真实的有三步,这里是为了体现两次握手的缺陷)
    第一步: 他要发送一条建立连接的消息告诉对方咱两要通信了
    第二步: 对方收到这个消息后,要回复他一个确认消息
    上面两步(两次握手)做完了,两人才能够通信

    于是,司马通过遵守TCP协议给上官天宇发了个”你好”,过了一会儿,他见上官没给他发确认消息
    于是他就按照TCP的超时重传机制[简单的说就是在一定的时间后,如果对方没有回应,就认为这个消息发送失败,要重新发送],然后司马就重新发了一个消息给上官了

    过了一小会,上官发来了确认消息,里面写着:“我收到了”(这个时候两次握手已经完成,两个人可以进行聊天了)
    然后上官也给司马发了一个“你好”,相互聊了几句,就关闭了连接(四次挥手在下篇说)

    殊不知过了一会,司马又收到聊了上官的确认消息,司马心中很纳闷,我没给他再发消息啊?喜欢探究原因的他把这个事情上报给TCP/IP的酋长了

    设计上的缺陷

    酋长带着问题来到了宫廷,见了专家组,专家组也很纳闷,想了许久,一个资深的元老突然说道,我们的设计可能有问题,现在我们的TCP是两次连接后就可以进行通信了,现在有这么一种情况,当A发送一个消息给B,这个消息由于网络的原因,阻塞在某个节点了,如下图

     

    然后阻塞的时间很长,超出了咱们设定超时重发时间,那么A就会认为这个消息丢失了,然后重新发送

    当A和B通信完成后,这个之前被A认为”失效的消息“到达了B,而对于B而言,以为这是一个新的请求连接消息,就向A发了一次确认(这就可以解释司马有收到了一次的确认消息了),而对于A而言,他认为他没有给B再次的发消息(因为上次的通话已经结束了),所以A不会理睬这条确认,但是B则会一直在傻傻的等待着A的消息

    这就导致了B的时间被白白浪费(对于服务器而言,就是CPU等资源的一种浪费),这样是万万不可的,这就是为什么不能两次握手的原因

    最终的修订

    专家组的人一致赞同这个观点,然后几个人还做了几个实验,结论是确实是这个原因导致的,最后专家组坐在一块讨论如何修改这个TCP协议,元老发话了,其实修改也很简单,再加一次通信(握手)就行了,如下图

    就是说A最后还要给B发一个确认,还是上次的那个例子,如果A不给B发第三次确认消息,那么B就认为A并没给他发消息,B也就不会在那里傻傻的等待了。最后酋长带着答案和修改草稿回到了部落。

    TCP四次挥手

      所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:

      由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。

     (1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

     (2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。

     (3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

     (4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。


     

      上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,具体流程如下图:

      流程和状态在上图中已经很明了了,在此不再赘述,可以参考前面的四次挥手解析步骤。

    容易理解的小故事

    酋长从宫中回来不久,国王就颁布了新的TCP协议法案,这次修正版的TCP协议运行的很好,举国上下一片喜悦

    从小白到菜鸟的转变

    经过上次的聊天后,司马和上官成为了好朋友,今天,司马又给上官发消息了,但是这次,两人建立连接后,同时给对方发送了一个报文“在吗?”,导致过了一会,司马和上官都收到对方的“在吗?”如下图:

     

    在聊天完后,好学的司马又去请教酋长去了,酋长说,TCP是允许你们同时给对方发消息的,这种特性有一个专业名字叫做“全双工”,“哦,原来是这样”,“司马恍然大悟。原来TCP里面的门道挺多”,下来得好好学习学习,司马心中暗自说道

    一次断开连接的历程

    司马又找好哥们上官聊天了,与往常一样,建立连接,聊完天后,断开连接。这次司马特别有心,用了一个小本子记录下这次TCP断开连接的过程。

    ① 刚开始,司马发了一个“连接释放报文段”表示自己不再发送聊天消息了
    ② 然后上官接到这个“连接释放报文段”后给司马发出一个“确认报文段”,表示自己收到了

    这时候,司马到上官方向的连接断了,即:司马没有消息给上官发了,但是上官到司马这个方向的连接还没有断,所以上官还可以给司马发送消息,他可能还有些话没说完。如下图:

     


    1>上官这时候如果没有啥消息给司马发了,那他也会发送一个“连接释放报文段”给司马,表明他想断开连接(上官到司马方向的连接)
    2>上官这时候如果还有消息想给司马发,那就按照往常一样把消息从他这边发给司马(因为从上官到司马这个方向的连接还没有断),等到发送完成后,然后再发送”连接释放报文段”

    ④ 司马收到这个报文后,也会给上官发送一个”确认报文段“以表明自己自己收到这个报文

    ⑤ 但是这个时候司马还不能撒手不管,他还需等待一段时间才可以进入到“CLOSED”(关闭)状态,表明自己的这次连接已经关闭了。可以接受下次连接了。

    ⑥ 当上官收司马的确认后,自己也进入“CLOSED”状态

    完整的TCP四次挥手如下图:

     

    司马心中的疑惑

    司马下来看了看小本子,心中产生了一个疑惑,为什么我最后一次给上官发送确认,我还需要等一段时间,我不想等这么长时间,多麻烦。

    他找酋长去诉苦去了,酋长说:“你等待这么长时间是有非常有必要的,你想啊,咱们TCP是不是规定了发出去的“请求报文(可能是请求连接,也有可能是请求关闭)”需要得到对方的确认,如果超过一定时间得不到确认会进行超时重传

    如果说你给上官发送的那个确认如果在中途丢失了,上官迟迟等不到你的确认,他肯定会执行超时重传给你重新发一个请求关闭连接的报文的,如果你不等待这么长时间而直接进入关闭状态,是不是就接收不到这个重传的报文了?那上官是不是就收不到你的确认,进而上官就不能正常关闭了?如下图:

     

    所以说,你在等的这段时间,其实是要确保你的确认让对方收到,如果对方超时重传一个连接释放报文段,这个时候你还没有关闭,那你就可以重新发一个确认给他呀”

    “哦,原来是这样呀”,司马心中的怨气立马就消失了。

    从此计算机帝国走向了互联网的时代

    思考:

      (1)三次握手是什么或者流程?四次握手呢?

    自己往上翻~

      (2)为什么建立连接是三次握手,而关闭连接却是四次挥手呢?

    解释1、由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。 

    解释2、这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

    注:参考来自以下,感谢

    地址1:https://blog.csdn.net/Mark2When/article/details/54956559

    地址2:https://blog.csdn.net/qq_30137611/article/details/77941313

  • 相关阅读:
    Python3三位运算
    PyThon3函数的使用
    PyThon3类的基本使用
    PyThon3类的继承
    Python3方法重写
    【BZOJ3307】雨天的尾巴-线段树合并+树上差分
    【CF893F】Subtree Minimum Query-主席树
    【BZOJ2212】Tree Rotations(POI2011)-平衡树启发式合并
    【BZOJ2733】永无乡(HNOI2012)-平衡树启发式合并
    【BZOJ3160】万径人踪灭-FFT+Manacher
  • 原文地址:https://www.cnblogs.com/it-taosir/p/9912397.html
Copyright © 2020-2023  润新知