计算机网络—TCP协议详解:协议构成、深度解析(2)

                                        🎬慕斯主页修仙—别有洞天

                                       ♈️今日夜电波:マリンブルーの庭園—ずっと真夜中でいいのに。

                                                           0:34━━━━━━️💟──────── 3:34
                                                                🔄   ◀️   ⏸   ▶️    ☰  

                                 💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


 

目录

连接管理机制

连接建立—三次握手

报文丢失的问题

为什么需要三次握手?

连接终止—四次挥手

为什么要等待 2MSL 呢?

谁先终止通信的问题

整体的理解三次握手和四次挥手

细节处理

accept的问题

listen的问题

处理服务器关闭后不能立即重启的问题


连接管理机制

        TCP(Transmission Control Protocol)是一种可靠的、面向连接的传输层协议,它提供了一种可靠的、字节流形式的数据传输服务。TCP连接管理机制包括连接建立、连接维护和连接终止等过程,主要通过三次握手和四次挥手来实现。

  1. 连接建立(Three-Way Handshake)
    • 第一步:客户端向服务器发送一个SYN(同步)包,表明客户端请求建立连接,并选择一个初始的序列号(这个序列号是随机的)。
    • 第二步:服务器收到客户端的SYN包后,会发送一个ACK(确认)包作为应答,并将确认号设置为客户端的序列号加1,同时也会发送一个SYN包给客户端,表明服务器也愿意建立连接,并选择一个初始的序列号。
    • 第三步:客户端收到服务器的SYN和ACK包后,会发送一个ACK包作为应答,确认收到了服务器的确认,并将确认号设置为服务器的序列号加1,此时连接建立完成。
  1. 连接维护
    • 一旦连接建立成功,TCP会维护连接的状态信息,包括序列号、确认号、窗口大小、拥塞窗口大小等。TCP使用序列号和确认号来保证数据的可靠传输,通过超时重传和选择性重传等机制来处理丢失的数据包,同时通过拥塞控制机制来避免网络拥塞。
  1. 连接终止(Four-Way Handshake)
    • 第一步:一方(通常是客户端)发送一个FIN包,表明它已经完成了所有数据的发送,并请求关闭连接。
    • 第二步:另一方(通常是服务器)收到FIN包后,会发送一个ACK包作为应答,确认收到了FIN包。
    • 第三步:服务器发送一个FIN包给客户端,表明服务器也已经完成了所有数据的发送,并请求关闭连接。
    • 第四步:客户端收到服务器的FIN包后,发送一个ACK包作为应答,确认收到了服务器的FIN包,此时连接关闭完成。

        TCP连接管理机制通过三次握手和四次挥手确保了连接的建立、维护和终止,保证了数据的可靠传输和网络的稳定性。下面对每一步进行详细的介绍:

连接建立—三次握手

        三次握手,我们以客户端向服务器请求建立连接为例:

        通过前面的学习我们知道SYN是一个请求连接的标志位,而ACK为响应连接,确认的标志位。

        客户端在一开始是没有任何状态的,也就是关闭状态的。当他要进行三次握手,同服务器建立连接时。只要把SYN发出去了(这个报文中包含了客户端的初始序列号(seq)),那么他的状态就会被置为SYN_SENT,也被称为同步发送。接着,只要服务器收到了连接请求报文,那么服务器的状态就会置为SYN_RCVD。接着他会回一个SYN+ACK的响应请求连接。

        后续客户端收到了服务器的报文后会返回一个ACK报文(期间他们的状态是没变的,保持SYN_SENT和SYN_RCVD),服务器在接收到客户端发送的ACK包后,服务器会进入到连接建立成功的状态,即ESTABLISHED状态,双方可以开始进行数据传输。大致的图示如下:

报文丢失的问题

        case1:若在客户端第一次向服务器请求连接时的SYN报文丢失,那么服务器不会受到任何影响,因为服务器并没有收到任何报文,而客户端则会超时重传。

        case2:若服务器向客户端响应的SYN+ACK报文丢失,那么可能会导致三次握手失败。而此之间,客户端等带服务器响应如果在一定时间内(通常是操作系统设定的默认超时时间)没有收到服务器的响应,则客户端会重新发送SYN包并重新开始计时等待。由于服务器已经将响应报文发出,那么服务器无法收到客户端的ACK确认,因此无法确定连接是否成功建立,也无法进入到下一个状态。这样的情况下,服务器会保持在SYN_RCVD状态,直到超时或者收到客户端的重传SYN包。这样最终可能就会引起客户端的重传行为。

        case3:若前面的报文都正常接受,但是客户端向服务器应答的ACK报文丢失,那么对于客户端来说,由于ACK已经发出,那么就认为三次握手成功了。但是对于服务器来说,只有收到了ACK才能认为成功建立连接。此时,

  1. 服务器处于半开放连接状态(半连接状态):服务器在接收到客户端发送的SYN包后,会向客户端发送SYN+ACK报文,并进入SYN_RCVD状态等待客户端的ACK确认。如果客户端发送的ACK报文丢失了,服务器无法收到客户端的确认,此时服务器处于半开放连接状态。在这种情况下,服务器等待一段时间后可能会超时,关闭连接。
  2. 服务器可能重传SYN+ACK报文:如果服务器在等待超时后仍未收到客户端的ACK确认,可能会重传SYN+ACK报文。服务器会继续重传,直到收到客户端的ACK确认或达到最大重传次数。
  3. 客户端认为建立好连接了,那么就会直接向服务器发信息,而服务器没建立好连接,当收到信息报文后,服务器就会立即重置连接,响应RST给客户端,双方会重新建立连接。大致的图示如下:

为什么需要三次握手?

        先明确一个目标:三次握手是为了建立连接。前两次握手都是验证客户端到服务端的通路是否通畅。这两次握手只是保证了一次收和发是成功的。也就说保证了客户端的收发是正常的,而服务器的收是正常的。那么只要客户端给服务器应答,服务器成功收到,也就说明服务器的发也是正常的。这样就验证了双方的通路是通畅的!验证了全双工的特效。

        如果只进行一次握手,那么客户端每发起一个建立连接请求,那么服务器都认为是建立成功的,服务器不需要响应应答。但是,客户端是有很多的,而服务器只有一个,很容易导致服务器连接资源被很快被占满的问题,影响后续的连接建立。这也被称为SYN洪水。

        如果只进行两次握手,也就是说明只要服务器给出了ACK应答那么就说明建立成功了。但是,如果这个应答客户端没有收到呢?那么客户端就会认为没建立成功,可是服务器认为建立成功了啊!(这与三次握手是相反的情况)这就导致服务器一直挂着大量的异常连接,导致连接异常的成本佳节给了服务器!

        所以,总结一下,三次握手是为了:1. 设计的优越性,一旦建立连接出现异常,成本嫁接到客户端,而不是由服务器承担,这样服务器建立失败的成本就会降低。2、减少SYN洪水的攻击可能。3. 能够验证双方的通信信道的通畅情况,验证双方全双工的特性。

连接终止—四次挥手

        为什么要进行四次挥手呢?这是因为断开的本质是双方都没有数据给对方发了,而双方都是有可能会给对方发数据的,所以要断开连接,就需要征得双方的同意,不能只征得一方,双方的地位是对等的,四次挥手可以是双方以最小成本断开。还是以客户端和服务器为例:

        通过前面的学习我们知道FIN表明此报文段的发送端的数据已发送完毕,并要求释放运输连接的标志位。

        如果要结束连接,那么就要发送FIN报文。客户端要结束连接,那么客户端先第一次挥手,发送FIN后,他的状态变为FIN_WAIT1(在这个状态下,客户端仍然可以接收来自服务器的数据,但不再发送数据),而服务器收到FIN报文后服务器状态变为CLOSE_WAIT(CLOSE_WAIT状态表示本地端已经收到了远程端发送的FIN包,并等待本地应用程序处理完毕数据,准备关闭连接)然后服务器第二次挥手向客户端回复ACK。客户端收到ACK后状态变为FIN_WAIT2(这个状态表明客户端已经发送了关闭连接的请求,并且收到了服务器的确认,但还没有收到服务器发送的FIN包)。接着如果服务器也想断开连接了就会第三次挥手向客户端发送FIN,接着服务器状态变为LAST_ACK(表示本地端不再发送数据)。客户端收到服务器的FIN后会第四次挥手向服务器回复ACK,然后进入TIME_WAIT状态(在这个状态下,表示连接已经被正常关闭,但为了确保数据传输的可靠性,本地端会等待一段时间后才能完全关闭连接)。而服务器收到ACK后直接进入CLOSE状态(CLOSE状态通常指的是连接已经完全关闭,不再接收或发送任何数据,且不再占用任何系统资源的状态)。客户端在TIME_WAIT后会等待2MSL(2MSL表示一个TCP报文在网络中的最长存活时间)才进入CLOSE状态。大致的图示如下:

        而在发送往最后一次ACK后客户端才认为完成四次挥手,而服务端在收到ACK后才会认为完成四次挥手。意味着:主动断开的一方一定是发送最后一次ACK的一方!

为什么要等待 2MSL 呢?
  1. 确保网络中所有数据包被丢弃:在网络中,数据包可能会因为延迟、重复或乱序而导致连接关闭过程中的混乱。等待 2MSL 的时间可以确保所有相关的数据包都已经被丢弃,从而避免在新的连接中出现问题。
  2. 防止旧连接数据干扰新连接:如果不等待足够长的时间,旧连接的数据包可能会混入到新连接中,导致数据错乱或错误。通过等待 2MSL,可以确保任何旧连接的残留数据都已经在网络中消失。
  3. 保证连接状态同步:在等待 2MSL 的过程中,连接的两端可以保持连接状态同步,确保双方都能正确地处理关闭连接的过程。

谁先终止通信的问题

        1.如果客户端是主动终止通信的一方,那么服务器在接收到FIN会变为CLOSE_WAIT状态,而客户端在接受应答后会变为FIN_WAIT2,如果不做下一步的动作,那么服务器为长时间保存CLOSE_WAIT。

        2.如果服务器是主动终止通信的一方,那么如果完成了所有的四次挥手动作,那么服务器将会处于TIME_WAIT状态,需要等待一段时间才会变为CLOSE状态,由于服务器IP+PORT正在被使用,这也就导致了我们如果在关闭服务器后想要马上重启会发送绑定端口失败的原因。那为什么客户端不会出现呢?因为客户端使用的是随机的端口号!

整体的理解三次握手和四次挥手

        理解完成完上面的知识,那么结合系统提供的接口,下面我们全面的理解三次握手和四次挥手的全过程:

 

细节处理

accept的问题

        在TCP/IP协议中,三次握手用于建立客户端和服务器之间的连接,而四次挥手则用于断开这个连接。accept函数在这个过程中对于上层起到了关键的作用。但是,实际上连接成功的与否与accept是没关系的。三次握手是双方在系统层自动完成的!accept是作为在双方建立成功连接后,对于上层的显示。

listen的问题

        前面的文章中我们提到listen函数原型通常如下:

#include <sys/types.h>  
#include <sys/socket.h>
int listen(int sockfd, int backlog);

其中

  • backlog:这是等待连接队列的最大长度。换句话说,这是可以等待处理的未完成连接请求的最大数量。当队列满时,新的连接请求可能会被拒绝。这个值通常设置为5或更大,但具体的值取决于你的应用需求和系统限制。

        现在再来理解一下backlog这个参数:这是可以等待处理的未完成连接请求的最大数量。当队列满时,新的连接请求可能会被拒绝。backlog参数告诉操作系统在内核中创建的连接队列的大小。连接队列用于存储已经到达但尚未被服务器accept调用接受的连接请求。当服务器正在处理连接时,新的连接请求会被放在这个队列中等待。默认的,我设置的允许建立连接的数量backlog+1。那么如果允许建立连接的数量满了,又来了新的建立连接怎么办呢?这里就在三次握手这里做文章了,服务端会在最后面也就是当服务端处于SYN_RECV的状态将本该接受的ACK报文给丢弃,这样这个连接就会处于SYN_RECV。但是客户端却认为是建立成功了处于上面提到的丢失报文的case3问题。但是服务端不会长时间的维持SYN_RECV状态(半连接状态),过一段时间会被消除。

        那么这个backlog是越大越好吗?为什么是不能设置过大也不能过小呢?这是因为

  1. 过大的backlog
    • 过大的backlog可能会占用过多的系统资源,导致服务器性能下降。每个挂起连接都需要一定的内存资源来维护,如果连接队列过大,会消耗大量的内存资源,影响服务器的正常运行。
    • 另一方面,即使设置了很大的backlog值,实际上服务器也可能无法处理大量的挂起连接,这取决于服务器的处理能力。如果服务器无法及时处理连接队列中的请求,那么增加backlog的大小也不会有太大的帮助。
  1. 过小的backlog
    • 过小的backlog可能会导致新的连接请求被拒绝,因为连接队列已经满了。如果服务器繁忙或者连接负载较高,过小的backlog会导致部分连接请求无法被及时处理,客户端可能会收到连接被拒绝的错误。

处理服务器关闭后不能立即重启的问题

        前面我们也提到过setsockopt这个函数:

    setsockopt 是一个用于设置套接字选项的系统调用,它允许程序员设置各种与套接字相关的参数,以控制套接字的行为和特性。下面是对 setsockopt 的详细解释:

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
    • sockfd:表示要设置选项的套接字文件描述符。
    • level:表示选项的级别,通常为 SOL_SOCKET,也可以是其他协议特定的值。
    • optname:表示要设置的选项名称。
    • optval:指向包含新选项值的缓冲区。
    • optlen:表示 optval 缓冲区的大小。
  1. 常用的选项
    • SO_REUSEADDR:允许在同一端口上启动多个套接字,用于解决 TIME_WAIT 状态下不能立即重用相同端口的问题。
    • SO_REUSEPORT :允许多个套接字在同一台主机上监听相同的 IP 地址和端口号,而不会因为地址和端口已经被占用而失败。
    • SO_KEEPALIVE:启用 TCP 的 keepalive 机制,检测连接是否仍然有效。
    • SO_LINGER:控制关闭连接时套接字的行为,可设置等待时间。
    • SO_SNDBUFSO_RCVBUF:设置发送和接收缓冲区的大小。
    • TCP_NODELAY:禁用 Nagle 算法,立即发送数据。
  1. 设置选项的值
    • 对于大多数选项,optval 是一个指向包含新选项值的缓冲区的指针。缓冲区中存储的是选项值的数据结构,其类型和格式取决于具体的选项。
    • optlen 表示 optval 缓冲区的大小,即选项值的长度。
  1. 返回值
    • 如果设置成功,setsockopt 返回 0。
    • 如果设置失败,返回 -1,并设置全局变量 errno 指示错误类型。

        我们可以设置如上的SO_REUSEADDR选项SO_REUSEPORT选项来解决这个问题。

        如下是一个例子:

int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt);

 


                       感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                       

                                                                        给个三连再走嘛~  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

M系Mac关闭SIP

文章目录 M系Mac关闭SIP一&#xff1a;查看SIP状态二&#xff1a;关闭SIP步骤 M系Mac关闭SIP 一&#xff1a;查看SIP状态 1、使用终端 打开终端 输入csrutil status&#xff0c;回车 你会看到以下信息中的一个&#xff0c;指示SIP状态 已打开 System Integrity Protection s…

Qt/C++音视频开发70-无感切换通道/无缝切换播放视频/多通道流畅切换/不同视频打开无缝切换

一、前言 之前就写过这个方案&#xff0c;当时做的是ffmpeg内核版本&#xff0c;由于ffmpeg内核解析都是代码实现&#xff0c;所以无缝切换非常完美&#xff0c;看不到丝毫的中间切换过程&#xff0c;看起来就像是在一个通道画面中。其实这种切换只能说是取巧办法&#xff0c;…

Spire.PDF for .NET【文档操作】演示:合并 PDF 文档

需要合并 PDF 的原因有很多。例如&#xff0c;合并 PDF 文件允许您打印单个文件&#xff0c;而不是为打印机排队多个文档&#xff0c;组合相关文件通过减少要搜索和组织的文件数量来简化管理和存储多个文档的过程。在本文中&#xff0c;您将学习如何使用Spire.PDF for .NET将多…

windows部署pgsql

1、下载&#xff1a;Download PostgreSQL Binaries 2、创建data目录作为数据目录 3、初始化 bin目录执行命令&#xff1a; .\initdb.exe -D E:\pgsql\data -E UTF-8 --localechs -U postgres -W 输入密码直到完成 4、启动数据库 .\pg_ctl.exe -D E:\pgsql\data -l logfil…

【基础】在GCC中编译和链接不是一个命令

在 GCC&#xff08;GNU Compiler Collection&#xff09;中&#xff0c;编译和链接不是一个命令。编译是将源代码转换为目标代码的过程。它主要进行语法检查、词法分析、生成中间代码等操作。链接是将多个目标文件和库文件组合成一个可执行文件的过程。在 GCC 中&#xff0c;通…

实战1-批量爬取百度图片(上)

任务需求&#xff1a;输入关键字下载100个图片保存到本地&#xff0c;每个关键字单独存放一个文件夹&#xff08;GUI版&#xff09; 任务描述&#xff1a;当输入关键字时会爬取100个与关键词有关的图片到本地每个关键词单独保存到一个文件夹中&#xff0c;比如说我输入黑客下载…

SpringBoot(二)【整合第三方技术】

1、SpringBoot 整合第三方框架 1.1、整合 JUnit 我们先回顾一下在学习 SpringMVC 的时候&#xff0c;我们当时整合 Spring 和 JUnit 是这么整合的&#xff1a; 注意&#xff1a;如果测试类在 SpringBoot 启动类的包或者子包中&#xff0c;可以省略启动类的设置&#xff0c;也…

【面试经典 150 | 二叉树层序遍历】二叉树的层平均值

文章目录 写在前面Tag题目来源题目解读方法一&#xff1a;层序遍历 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行…

设计模式——策略模式20

策略模式是一种行为设计模式&#xff0c; 它能让你定义多种算法或行为方式&#xff0c; 并将具体实现放入独立的类中&#xff0c; 以使算法的对象能够相互替换。使用场景例如活动中多种打折策略。 策略抽象 /*** author ggbond* date 2024年04月18日 08:02*/ public interfa…

Hive进阶(1)----HDFS写入数据流程(赋图助君理解)

HDFS写入数据流程 1.理论流程描述 HDFS&#xff08;Hadoop分布式文件系统&#xff09;的数据写入流程是一个复杂但高效的过程&#xff0c;可以分为以下8个步骤&#xff1a; 1、client(客户端)发起文件上传请求&#xff1b; 2、通过发送RPC请求与NameNode建立通讯。NameNode…

【MySQL篇】mysqlpump和mysqldump参数区别总汇(第三篇,总共四篇)

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&am…

递归 python

↵一、简单理解 解决问题的一种方法&#xff0c;它将问题不断的分成更小的子问题&#xff0c;直到子问题可以用普通的方法解决。通常情况下&#xff0c;递归会使用一个不停调用自己的函数。 【注】&#xff1a;每一次递归调用都是在解决一个更小的问题&#xff0c;如此进行下…

内核编译-02

1配置【u-boot】 查看版本信息 对arm文件进行编译的专用工具 打开脚本文件 配置脚本文件 编译【.c】文件 创建目录&#xff0c;解压文件夹&#xff1a; 编译【smdk2440_config】&#xff0c;并产生【u-boot.bin】&#xff1a; 2配置开发板对应的配置文件 这里采用菜单…

基于深度学习的光场超分辨率算法综述

摘要&#xff1a;光场图像分辨率低的原因之一是光场空间分辨率和角度分辨率之间存在相互制约。光场超分辨率技术旨在从低分辨率光场图像中重建出高分辨率光场图像。基于深度学习的光场超分辨率方法通过学习高、低分辨率光场图像之间的映射关系来提升图像的质量&#xff0c;突破…

亚马逊Bedrock凭借Anthropic的开创性Claude 3系列扩展了AI产品组合

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

云服务器部署Springboot项目

前端项目打包 修改ip地址 在控制台输入npm run build:prod 会产生dist文件 将dist文件中的内容移动至/usr/local/nginx/html目录下 后端项目打包 修改ip地址 执行clean操作 执行install操作 将生成的target文件中的jar包移动至/usr/local/src目录下 启动 注意⚠️&#xff…

动态规划-不同路径

LCR 098. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 对于动态规划类型的题目&#xff0c;可以从以下角度去思考问题 1. 状态表示 机器人在每一个网格节点的状态 dp[i][j] &#xff0c;可以理解从 起始点 为走到 [i,j] &#xff0c;一共有多少种方式&#xff1b; 2. …

vscode按ctrl+鼠标左键没反应

vscode按ctrl鼠标左键没反应 问题问题解决 问题 新买的阿里云服务器,在连接vscode后,按ctrl鼠标左键没反应,怎么办? 问题解决 你没有在vscode上安装c的相关插件,安装之后才可以实现按ctrl鼠标左键跳转到函数的定义

硬件设备杂记——12G SDI及 AES67/EBU

常见的 SDI线缆规格&#xff0c;HD-SDI又被称为1.5G-SDI&#xff0c;具体参数以秋叶原的参数为例 AES67/EBU 目前音频网络标准主要集中在OSI网络体系的第二层和第三层。 第二层音频标准的弊端在于构建音频网络时需要专用的交换机&#xff0c;无法利用现有的以太网络&#xff0c…

Matlab|【免费】【sci】考虑不同充电需求的电动汽车有序充电调度方法

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序复现sci文献《A coordinated charging scheduling method for electric vehicles considering different charging demands》&#xff0c;主要实现电动汽车协调充电调度方法&#xff0c;该方法主要有以…