• 刷题分享—常见的经典面试题二


    ✅作者简介:嵌入式领域新星创作者,博客专家
    ✨个人主页:咸鱼弟
    🔥 系列专栏:剑指offer专栏

    目录

    题干 :请你说说 TCP 三次握手四次挥手过程

    得分点

    标准回答

    加分回答


    题干 :请你说说 TCP 三次握手四次挥手过程

    解题思路

    得分点

    第一、二次分别包含数据通讯初始序号。第三次是必须的,为了防止已经失效的连接请求报文突然又被传送给了服务器端,然后产生错误。TCP是全双工通讯,客户端和服务器端都需要释放连接和接受确认,所以必须是四次挥手。

    标准回答

    三次握手过程:第一次握手:客户端向服务器端发送连接请求报文段,包含自身数据通讯初始序号,进入SYN-SENT状态。

    第二次握手:服务器端收到连接请求报文段后,如果同意,发送应答,包含自身数据通讯初始序号,进入SYN-RECEIVED状态。

    第三次握手:客户端收到应答,最后向服务器端发送确认报文,进入ESTABLISHED状态,此时成功建立长连接。

    四次挥手过程:

    首先第一次挥手:客户端认为数据发送完毕,需要向服务器端发送连接释放请求。

    第二次挥手:服务器收到连接释放请求,告诉应用层释放TCP连接。然后发送ACK包,进入CLOSE-WT状态,此时表明客户端到服务器端的连接已经释放,不再接受客户端的数据。因为TCP是全双工的,所以服务器仍可以发送数据。

    第三次挥手:当服务器端数据发送完毕,向客户端发送连接释放请求,进入LAST-ACK状态。第四次挥手:客户端收到连接释放请求,向服务器端发送确认应答报文,此时客户端进入TIME-WT状态,持续2倍的MSL(最长报文段寿命),若期间没有收到服务器端的数据报文,进入CLOSED状态。服务器端收到确认应答后,也进入CLOSED状态。

    加分回答

    以下是客户端向服务器端发起TCP连接的详细过程:

    1. 客户端和服务器端刚开始都是处于CLOSED(关闭)状态。

    2. 要注意的是客户端主动打开连接,而服务器端是被动打开连接的。

    3. 服务器端的进程先创建TCB(传输控制块)准备接受客户端的连接请求。

    4. 客户端的进程也是先创建TCB(传输控制块),然后向服务器端发出连接请求报文段,这个报文段中的同步位SYN置为1,同时选择一个初始序号seq=x。TCP协议规定了SYN=1的报文段不可以携带数据,但是要消耗掉一个序号。这个时候客户端进入SYN-SENT状态。

    5. 服务器端收到连接请求报文之后,如果同意连接,就给客户端发送确认响应。在确认报文中应该将同步位SYN和ACK都置为1,而确认号是ACK+1。这时候服务器端也需要给自己选一个初始序号seq=y。值得注意的是这个确认报文也不能携带数据,同样要消耗掉一个序号。这时服务器端进入SYN-RECEIVED状态。

    6. 客户端进程收到服务器端的确认报文,最后还要向服务器端给出确认。确认报文段的ACK置为1,确认号是y+1,而自己的序号seq=x+1。TCP标准规定,ACK报文段可以携带数据,但是如果不携带数据就不消耗序号。在这个情况下,下一个数据报文的序号仍然是seq=x+1。到这时,TCP连接已经成功建立,A进入ESTABLISHED(已建立连接)状态。

    到此TCP连接三次握手的过程就全部结束了。但是为什么一定要三次握手而不是两次,为什么客户端最后还需要发送一次确认报文呢?其实主要是为了防止已经失效的连接请求报文突然又被传送给了服务器端,然后产生错误。假设现在有一种情况,客户端发出的第一个连接请求报文段并没有丢失而是在某些网络节点上被滞留了,直到客户端和服务器端的新连接已经释放后的某个时间点,第一个连接请求报文段才到了服务器端,这时候服务器端以为客户端又发起了一次请求,于是服务器端向客户端发起了确认连接报文段,同意连接。假设不采用三次握手,这时候连接已经建立了,但是客户端并不知道这个情况,服务器端会一直等待客户端的数据报文,这样服务器端的资源就会被浪费,占用大量的资源。所以采用三次握手可以防止这种现象,保护网络和系统资源。 TCP连接释放的过程比较复杂,客户端和服务器端都可以主动释放连接。

    下面是从客户端主动释放连接为例讲解四次挥手的详细过程:

    1. 客户端的应用进程先向TCP发出一个连接释放报文段,然后停止发送数据报,主动关闭TCP连接。客户端需要将连接释放报文段首部的终止控制FIN置为1,序号设置为u,u相当于前面传输的数据报文段的最后一个字节的序号加1。这时候客户端进入FIN-WT-1(终止等待1)状态,等待服务器端的确认。需要注意的是,FIN报文段也是即使不携带数据,它也消耗一个序号。

    2. 服务器在收到客户端发来的连接释放报文段请求之后就发出确认,确认号ack=u+1,这个报文段自己的序号是v,v相当于之前已经传送出去的最后一个报文段的序号加1。这时候服务器端进入CLOSE-WT(关闭等待)状态,这时候服务器端的TCP进程就要通知应用进程,客户端到服务器端的连接已经关闭了。需要注意的是,这个时候的TCP连接就处于一个半关闭(half-colse)的状态,尽管客户端已经没有数据要发送了,但是服务器端还是可以向客户端发送数据的,服务器端到客户端的连接并没有被释放掉。

    3. 如果服务器端也没有数据要发送给客户端了,那么应用进程就通知TCP释放连接。这时候服务器端发出的连接释放报文段请求的终止指令FIN也置为1。这时候服务器端的序号已经是w了,因为在半关闭状态服务器端可能又发送了一些数据,服务器也必须重复上次已经发送过的确认号ack=u+1。这时候服务器端进入LAST-ACK(最后确认)状态,等待客户端的确认。

    4. 客户端收到服务器端的连接释放请求报文段之后,必须发出确认。在确认报文段中把ACK置为1,确认号ack=w+1,而自己的序号是seq=u+1(根据TCP标准,FIN消耗了一个序号),然后进入TIME-WT(时间等待)状态,这时候连接并没有释放掉,必须等到2倍的MSL(最长报文段寿命)之后,连接才会释放。

    本次就分享到这里,这道题非常经典也很常见,很多公司都出过这道题,所以值得大家看一看,最后预祝大家面试成功! 

  • 相关阅读:
    Nextcloud删除动态/活动日志(activity log)
    Spark SQL 从入门到精通 - Spark SQL 行转列、列转行案例
    JumpServer未授权访问漏洞 CVE-2023-42442
    顺丰旗下丰鸟无人机高薪诚聘海内外英才
    优化sql语句的一般步骤
    C++奇迹之旅:深入思考拷贝构造函数
    第一百五十八回 SliverGrid组件
    FasterViT:基于分层注意力的快速视觉transformer
    leetcode523. 连续的子数组和python_哈希表和前缀和
    cmdb运维管理平台,IT资源配置管理
  • 原文地址:https://blog.csdn.net/u013253075/article/details/126445262