热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[转]面试官,不要再问我三次握手和四次挥手

学习转载自https:blog.csdn.nethyg0811articledetails102366854#23_2MSL_131 [阅前思考]1.请画出三次握手和四次握手的示意

学习转载自https://blog.csdn.net/hyg0811/article/details/102366854#23_2MSL_131

 

[阅前思考]

1.请画出三次握手和四次握手的示意图?

2.为什么连接的时候是三次握手?

3.什么是半连接队列?

4.ISN(Initial Sequence Number)是固定的吗?

5.三次握手过程中可以携带数据嘛?

6.如果第三次握手丢失了 客户端服务端会如何处理?

7.SYN攻击是什么?

8.挥手为什么需要四次?

9.四次挥手释放链接时.等待2MSL的意义?

 


1.三次握手

三次握手(Three_way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包。进行三次握手的主要作用就是确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。

 

刚开始客户端处于Closed状态,服务端处于Listen状态。

进行三次握手:



  • 第一次握手:客户端给服务端发送一个SYN报文,并指明客户端的初始化序列号ISN(c)。此时客户端处于SYN_SEND状态。

    首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。



  • 第二次握手:服务器收到客户端的SYN报文之后,会以自己的SYN报文作为应答,并且也是指定了自己的初始化序列号ISN(s)。同时会把客户端的ISN+1作为ACK的值,表示自己已经收到了客户端的SYN,此时服务器处于SYN_REVD状态。

    在确认报文段中SYN=1,ACK1,确认号ack = x+1,初始序号seq=y。



  • 第三次握手:客户端收到SYN报文后,回答送一个ACK报文,当然,也是一样把服务器的ISN+1作为ACK的值,表示已经收到了服务端的SYN报文,此时客户端处于ESTABLISHED状态。服务器收到ACK报文后,也处于ESTABLISHED状态,此时,双方已建立起了连接。

    确认报文ACK=1,确认号ack=y+1,序号seq=x+1(初始seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。

 

  发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open。

  在socket编程中,客户端执行connect()时,将触发三次握手。

  


  1.1 为什么需要三次握手,两次不行吗?

  弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。



  • 第一次握手:客户端发送网络包,服务器收到了。

    这样服务器就能得出结论:客户端的发送能力、服务器的接收能力是正常的。



  • 第二次握手:服务器发包,客户端收到了。

    这样客户端就能得出结论:服务器的接收能力、发送能力,客户端的接收、发送能力是正常的。不过此时服务器不能确认客户端的接收能力是否正常。



  • 第三次握手:客户端发包,服务器收到了。

    这样服务器就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

 

  因此,需要三次握手才能确认双方的接收与发送能力是否正常。

  试想如果是两次握手,则会出现下面这种情况:

    如果客户端发出连接请求,但因连接请求报文丢失而未收到确认木鱼石客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络节点长时间滞留了,延误到连接释放以后的某个时间才到达服务器,此时服务端误认为客户端又发出一次新的连接请求,于是就像客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务器发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一直等待客户端发出数据,浪费资源。


  1.2 什么是半连接?

  服务器第一次收到客户端的SYN之后,就会处于SYN_RCVD状态,此时双方还没有完全建立连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列

  当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。

  这里补充一点关于SYN-ACK重传次数的问题:

   服务器发送完SYN-ACK包,如果未收到客户端的确认包,服务器进行首次重传,等待一段时间仍未收到客户端确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。

   注意,每次重传等待的时间不一定相同,一般会是指数增长,例如时间间隔为1s,2s,4s,8s...


  1.3 ISN(Initial Sequence Number)是固定的吗?

  当一段为建立连接而发送他的SYN时,他为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。ISN可以看做一个32bit的计数器,每4ms加1。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送到,而导致某个连接的一方对她做出错误的解释。

  三次握手的其中一个重要功能是客户端和服务端交换ISN,以便让对方知道接下来接收数据的时候如何按照序列号组装数据。如果ISN是固定的,攻击者很容易猜出后续的确认号,因此ISN是动态生成的。


  1.4 三次握手过程中可以携带数据吗?

  其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据

  为什么这样呢?试想,例如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的SYN报文中放入大量数据。因为攻击者根本就不理副武器的接受、发送能力是否正常,然后疯狂的重复发SYN报文的话,这会让服务器花费很多时间、内存空间来接受这些报文。

  也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更容易受到攻击了。而第三次的话,此时客户端已经处于ESTABLISHED状态了。对于客户端来水,他已经建立起连接了,并且已经知道服务器的接收、发送能力正常的,所以能携带数据也没啥毛病。


  1.5 SYN攻击是什么?

  服务器的资源分配是在第二次握手时分配的,而客户端的资源实在完成三次握手时分配的,所以服务器容易受到SYN洪犯攻击。SYN攻击就是client在短时间内伪造大量不存在的IP地址,并向server不断的发送SYN包,sever则回复确认包,并等待client确认,由于源地址不存在,因此sever需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYn攻击是一种典型的Dos/DDos攻击。

  检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源地址是随机的,基本上可以断定这是一次SYN攻击。在linux/unix上可以使用系统自带的netstats命令来检测SYN攻击。

netstat -n -p TCP | grep SYN_RECV

  常见的防御SYN攻击的方法有如下几种:

  缩短超时(SYN Timeout)时间

  增加最大半连接数

  过滤网关防护

  SYN COOKIEs技术

 

 


2.四次挥手

建立一个连接需要三次握手,而终止一个连接需要经过四次挥手。这由TCP 的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束他的发送后还能接收来自另一端数据的能力。

TCP的连接的拆除需要发送四个包,因此成称为四次挥手(Four-way handshake),客户端或服务器端均可主动发起挥手动作。

 

刚开始双方都处于ESTABLISHED状态,假如是客户端先发起关闭请求。四次挥手的过程如下:



  • 第一次挥手:客户端发送一个FIN报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态。

    即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务器的确认。



  • 第二次握手:服务器收到FIN之后,会发送ACK报文,且把客户端的序列号值+1作为ACK报文的序列号值,表明已经接收到客户端的报文了 ,此时服务器处于CLOSE_WAIT状态。

    即服务器收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务器进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半连接状态,客户端到服务器的连接释放。客户端收到服务器的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务器发出的连接释放报文段。



  • 第三次挥手:如果服务器也想断开连接了,和客户端的第一次挥手一样,发送FIN报文,且指定一个序列号。此时服务端处于LAST_ACK的状态。

    即服务端没有要想客户端发出的数据,服务端发出连接释放报文段(FIn=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态。等待客户端的确认。



  • 第四次挥手:客户端收到FIN后,一样发送一个ACK作为应答,且把服务器的序列号值+1作为自己ACK报文的序列号值,此时客户端处于TIME_WAIT状态。需要过一阵子以确保服务端收到自己的ACK报文后才会进入CLOSED状态,服务端收到ACK报文之后,就处于关闭连接了,处于CLOSED状态。

  即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。

 

收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT1是正常的,服务器端通常执行被动关闭,不会进入TIME_WAIT状态。

在socket编程中,任何执行close()操作即可产生挥手操作。

 


  2.1 挥手为什么需要四次?

  因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭socket,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了,只有等到我服务端的所有的报文都发送完了,我才能发送FIN报文”,因此不能一起发送。故需要四次挥手。


  2.2 2MSL等待状态

  TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间(Maximum Segment Lifttime),他是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCp报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。

  对一个具体实现缩给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可以让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN )。

  这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,定义这个连接的插口(客户的IP地址和端口号,服务器的IP地址和端口号)不能再被使用。这个连接只能在2MSL结束后才能再被使用。


  2.3 四次挥手释放连接时,等待2MSL的意义?

  MSL(Maximum Segment Lifetime),意为“最长报文段寿命”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

  为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST_ACK状态的服务器收不到FIN_ACK报文。服务器会超时重传这个FIN_ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后立即释放关闭,一旦这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。

  两个理由:

    1.保证客户端发送的最有一个ACK报文段能够到达服务器。

    这个ACK报文段有可能丢失,是的处于LAST_ACK状态的另一端收不到已发送的SIN_ACK报文段确认,服务器超时重传FIN_ACK报文段,而客户端能在2MSL时间内收到这个重传的FIN_ACK报文段,接着客户端重传一次确认,重新启动2MSL计时器,最后客户端和服务器都进入到CLOSED状态,若客户端在TIE_WAIT状态下不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到服务器重传的FIN_ACK报文段,所以不会再发送一次确认报文段,则服务器无法正常进入CLOSED状态。

    2.防止“已失效的连接请求报文段”出现在本连接中。

    客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以是本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。


  2.4 为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?

  理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文

 

 


3.总结

《TCP/IP详解 卷1:协议》有一张TCP状态变迁图,很具有代表性,有助于大家理解三次握手和四次挥手的状态变化。如下图所示,粗的实线箭头表示正常的客户端状态变迁,粗的虚线箭头表示正常的服务器状态变迁。

    

 



推荐阅读
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了5个基本Linux命令行工具的现代化替代品,包括du、top和ncdu。这些替代品在功能上进行了改进,提高了可用性,并且适用于现代化系统。其中,ncdu是du的替代品,它提供了与du类似的结果,但在一个基于curses的交互式界面中,重点关注占用磁盘空间较多的目录。 ... [详细]
  • 【重识云原生】第四章云网络4.8.3.2节——Open vSwitch工作原理详解
    2OpenvSwitch架构2.1OVS整体架构ovs-vswitchd:守护程序,实现交换功能,和Linux内核兼容模块一起,实现基于流的交换flow-basedswitchin ... [详细]
  • 面试经验分享:华为面试四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试
    最近有朋友去华为面试,面试经历包括四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试。80%的人都在第一轮电话面试中失败,因为缺乏基础知识。面试问题涉及 ... [详细]
  • 本文详细介绍了在Linux虚拟化部署中进行VLAN配置的方法。首先要确认Linux系统内核是否已经支持VLAN功能,然后配置物理网卡、子网卡和虚拟VLAN网卡的关系。接着介绍了在Linux配置VLAN Trunk的步骤,包括将物理网卡添加到VLAN、检查添加的VLAN虚拟网卡信息以及重启网络服务等。最后,通过验证连通性来确认配置是否成功。 ... [详细]
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 关于CMS收集器的知识介绍和优缺点分析
    本文介绍了CMS收集器的概念、运行过程和优缺点,并解释了垃圾回收器的作用和实践。CMS收集器是一种基于标记-清除算法的垃圾回收器,适用于互联网站和B/S系统等对响应速度和停顿时间有较高要求的应用。同时,还提供了其他垃圾回收器的参考资料。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有