Linux - 第19节 - 网络基础(传输层二)

news2024/11/19 0:32:41

1.TCP相关实验

1.1.理解listen的第二个参数

在编写TCP套接字的服务器代码时,在进行了套接字的创建和绑定之后,需要调用listen函数将创建的套接字设置为监听状态,此后服务器就可以调用accept函数获取建立好的连接了。其中listen函数的第一个参数就是需要设置为监听状态的套接字,而listen的第二个参数我们一般设置为5,那你知道listen函数的第二个参数具体的含义是什么吗?

下面通过一个实验来说明listen的第二个参数的具体含义。

创建server.hpp文件,如下图一所示,创建main.cc文件,如下图二所示,创建makefile文件,如下图三所示。使用make命令生成server可执行程序,使用./server 8080命令运行server可执行程序。登陆另一台云服务器作为客户端,创建四个选项卡,每个选项卡都使用 telnet 120.78.126.148 8080命令连接服务端,在服务端新建选项卡,使用netstat -ntp命令查看服务端连接状态,如下图四所示。

先编写TCP套接字的服务器端代码,服务器初始化时依次进行套接字创建、绑定、监听,但服务器初始化后不调用accept函数获取底层建立好的连接。
为了方便验证,这里将listen函数的第二个参数设置为2。

从下图三可以看出,客户端向服务端发送的前三个连接请求可以正常三次握手建立连接,连接的状态为ESTABLISHED,客户端向服务端发送的第四个连接请求开始,新连接的状态为SYN_RECV,也就是说从第四个客户端连接请求开始,服务端不再向客户端发送第二次握手的报文,只有前面的连接断开后,服务端才会再向客户端发送第二次握手的报文。这是因为我们设置了listen函数第二个参数为2,并且我们没有调用accept函数。

listen函数第二个参数叫做底层的全连接队列长度,当第二个参数值为n时,底层的全连接队列长度就为n+1。底层的全连接队列长度表示在不accept的情况下,最多能够维护的连接数。

注:服务器即使不调用accept函数,连接(三次握手)依然可以正常建立,accept函数并不参与三次握手,accept函数只是将底层已经成功三次握手建立的连接拿上来而已。

总结一下上面的实验现象:

• 全连接队列(accept队列)。全连接队列用于保存处于ESTABLISHED状态,但没有被上层调用accept取走的连接。
• 半连接队列。半连接队列用于保存处于SYN_SENT和SYN_RCVD状态的连接,也就是还未完成三次握手的连接。
而全连接队列的长度实际会受到listen第二个参数的影响,一般TCP全连接队列的长度就等于listen第二个参数的值加一。

因为我们实验时设置listen第二个参数的值为2,此时在服务器端全连接队列的长度就为3,因此服务器最多只允许有三个处于ESTABLISHED状态的连接。

如果将刚才代码中listen的第二个参数值设置为3,此时服务器端最多就允许存在4个处于ESTABLISHED状态的连接。在服务器端已经有4个ESTABLISHED状态的连接的情况下,再有客户端发来建立连接请求,此时服务器端就会新增状态为SYN_RCVD的连接,该连接实际就是放在半连接队列当中的。

此后就算再有客户端发来连接请求,在服务器端也不会新增任何状态的连接。

问题1:为什么底层要维护连接队列?

答:一般当服务器压力较大时连接队列的作用才会体现出来,如果服务器压力本身就不大,那么一旦底层有连接建立成功,上层就会立马将该连接读走并进行处理。

• 服务器端启动时一般会预先创建多个服务线程为客户端提供服务,主线程从底层accept上来连接后就可以将其交给这些服务线程进行处理。
• 如果向服务器发起连接请求的客户端很少,那么连接一旦在底层建立好就被主线程立马accept上来并交给服务线程处理了。
• 但如果向服务器发起连接请求的客户端非常多,当每个服务线程都在为某个连接提供服务时,底层再建立好连接主线程就不能获取上来了,此时底层这些已经建立好的连接就会被放到连接队列当中,只有等某个服务线程空闲时,主线程就会从这个连接队列当中获取建立好的连接。
• 如果没有这个连接队列,那么当服务器端的服务线程都在提供服务时,其他客户端发来的连接请求就会直接被拒绝。
• 但有可能正当这个连接请求被拒绝时,某个服务线程提供服务完毕,此时这个服务线程就无法立马得到一个连接为之提供服务,所以一定有一段时间内这个服务线程是处于闲置状态的,直到再有客户端发来连接请求。
• 而如果设置了连接队列,当某个服务线程提供完服务后,如果连接队列当中有建立好的连接,那么主线程就可以立马从连接队列当中获取一个连接交给该服务线程进行处理,此时就可以保证服务器几乎是满载工作的。

问题2:为什么连接队列不能太长?

答:全连接队列不能太长,系统一般设置为5。虽然维护连接队列能让服务器处于几乎满载工作的状态,但连接队列也不能设置得太长。

• 如果队列太长,也就意味着在队列较尾部的连接需要等待较长时间才能得到服务,此时客户端的请求也就迟迟得不到响应。
• 此外,服务器维护连接也是需要成本的,连接队列设置的越长,系统就要花费越多的成本去维护这个队列。
• 但与其与其维护一个长连接,造成客户端等待过久,并且占用大量暂时用不到的资源,还不如将部分资源节省出来给服务器使用,让服务器更快的为客户端提供服务。
因此虽然需要维护连接队列,但连接队列不能维护的太长。

全连接队列的长度

全连接队列的长度由两个值决定:

• 用户层调用listen时传入的第二个参数backlog。

• 系统变量net.core.somaxconn,默认值为128。

通过sysctl -a | grep net.core.somaxconn命令可以查看系统变量net.core.somaxconn的值,如下图所示。

全连接队列的长度实际等于listen传入的backlog和系统变量net.core.somaxconn中的较小值加一。

SYN洪水攻击:

连接正常建立的过程:

• 当客户端向服务器发起连接建立请求后,服务器会对其进行SYN+ACK响应,并将该连接放到半连接队列(syns queue)当中。
• 当服务器发出的SYN+ACK得到客户端响应后,就会将该连接由半连接队列移到全连接队列(accept queue)当中。
• 此时上层就可以通过调用accept函数,从全连接队列当中获取建立好的连接了。

连接建立异常:

• 但如果客户端在发起连接建立请求后突然死机或掉线,那么服务器发出的SYN+ACK就得不到对应的ACK应答。
• 这种情况下服务器会进行重试(再次发送SYN+ACK给客户端)并等待一段时间,最终服务器会因为收不到ACK应答而将这个连接丢弃,这段时间长度就称为SYN timeout。
• 在SYN timeout时间内,这个连接会一直维护在半连接队列当中。

此时服务器虽然需要短暂维护这些异常连接,但这种情况毕竟是少数,不会对服务器造成太大影响。

但如果有一个恶意用户故意大量模拟这种情况:向服务器发送大量的连接建立请求,但在收到服务器发来的SYN+ACK后故意不对其进行ACK应答。

• 此时服务器就需要维护一个非常大的半连接队列,并且这些连接最终都不会建立成功,也就不会被移到全连接队列当中供上层获取,最后会导致半连接队列越来越长。
• 当半连接队列被占满后,新来的连接就会直接被拒绝,哪怕是正常的连接建立请求,此时就会导致正常用户无法访问服务器。
• 这种向服务器发送大量SYN请求,但并不对服务器的SYN+ACK进行ACK响应,最终可能导致服务器无法对外提供服务,这种攻击方式就叫做SYN洪水攻击(SYN Flood)。

如何解决SYN洪水攻击:

首先这一定是一个综合性的解决方案,TCP作为传输控制协议需要对其进行处理,而上层应用层也要尽量避免遭到SYN洪水攻击。

• 比如应用层可以记录,向服务器发起连接建立请求的主机信息,如果发现某个主机多次向服务器发起SYN请求,但从不对服务器的SYN+ACK进行ACK响应,此时就可以对该主机进行黑名单认证,此后该主机发来的SYN请求一概不进行处理。
TCP为了防范SYN洪水攻击,引入了syncookie机制:

• 现在核心的问题就是半连接队列被占满了,但不能简单的扩大半连接队列,就算半连接队列再大,恶意用户也能发送更多的SYN请求来占满,并且维护半连接队列当中的连接也是需要成本的。
• 因此TCP引入了syncookie机制,当服务器收到一个连接建立请求后,会根据这个SYN包计算出一个cookie值,将其作为将要返回的SYN+ACK包的初始序号,然后将这个连接放到一个暂存队列当中。
• 当服务器收到客户端的ACK响应时,会提取出当中的cookie值进行对比,对比成功则说明是一个正常连接,此时该连接就会从暂存队列当中移到全连接队列供上层读取。

引入了syncookie机制的好处:

• 引入syncookie机制后,这些异常连接就不会堆积在半连接队列队列当中了,也就不会出现半连接队列被占满的情况了。
• 对于正常的连接,一般会立即对服务器的SYN+ACK进行ACK应答,因此正常连接会很快建立成功。
• 而异常的连接,不会对服务器的SYN+ACK进行ACK应答,因此异常的连接最终都会堆积到暂存队列当中。

1.2.理解CLOSE_WAIT状态

当客户端和服务器在进行TCP通信时,如果客户端调用close函数关闭对应的文件描述符,此时客户端底层操作系统就会向服务器发起FIN请求,服务器收到该请求后会对其进行ACK响应。

但如果当服务器收到客户端的FIN请求后,服务器端不调用close函数关闭对应的文件描述符,那么服务器就不会给客户端发送FIN请求,相当于只完成了四次挥手当中的前两次挥手,此时客户端和服务器的连接状态分别会变为FIN_WAIT_2和CLOSE_WAIT。

下面我们可以编写一个简单的TCP套接字来模拟出该现象,实际我们只需要编写服务器端的代码,而采用一些网络工具来充当客户端向我们的服务器发起连接请求。

创建server.hpp文件,如下图一所示,创建main.cc文件,如下图二所示,创建makefile文件,如下图三所示。使用make命令生成server可执行程序,使用./server 8080命令运行server可执行程序。创建新选项卡作为客户端,在新选项卡使用 telnet 127.0.0.1 8080命令连接服务端后,再quit断开连接,再创建新选项卡,使用netstat -ntp命令查看服务端和客户端连接状态,如下图四所示。

服务器的初始化需要进行套接字的创建、绑定以及监听,然后主线程就可以通过调用accept函数从底层获取建立好的连接了。获取到连接后主线程创建新线程为该连接提供服务,而新线程只需执行一个死循环逻辑即可。

这两条连接当中,一条是客户端到服务器的连接,另一条就是服务器到客户端的连接。

现在我们让telnet退出,就相当于客户端向服务器发起了连接断开请求,但此时服务器端并没有调用close函数关闭对应的文件描述符,所以当telnet退出后,客户端维护的连接的状态会变为FIN_WAIT_2,而服务器维护的连接的状态会变为CLOSE_WAIT。

1.3.理解TIME_WAIT状态

当客户端和服务器在进行TCP通信时,客户端调用close函数关闭对应的文件描述符,如果服务器收到后也调用close函数进行了关闭,那么此时双方将正常完成四次挥手。

但主动发起四次挥手的一方在四次挥手后,不会立即进入CLOSED状态,而是进入短暂的TIME_WAIT状态等待若干时间,最终才会进入CLOSED状态。

创建server.hpp文件,如下图一所示,创建main.cc文件,如下图二所示,创建makefile文件,如下图三所示。使用make命令生成server可执行程序,使用./server 8080命令运行server可执行程序。创建新选项卡作为客户端,在新选项卡使用 telnet 127.0.0.1 8080命令连接服务端后,再quit断开连接,客户端断开后服务端ctrl c关闭,再创建新选项卡,使用netstat -ntp命令查看服务端和客户端连接状态,如下图四所示。

这里我们可以继续刚才的实验,由于telnet退出后服务器端没有调用close关闭对应的文件描述符,因此客户端维护的客户端维护连接的状态停留在了FIN_WAIT_2状态,而服务器维护连接的状态停留在了CLOSE_WAIT状态。

要让客户端和服务器继续完成后两次挥手,就需要服务器端调用close函数关闭对应的文件描述符。虽然服务器代码当中没有调用close函数,但因为文件描述符的生命周期是随进程的,当进程退出的时候,该进程所对应的文件描述符都会自动关闭。

因此只需要在telnet退出后让服务器进程退出就行了,此时服务器进程所对应的文件描述符会自动关闭,此时服务器底层TCP就会向客户端发送FIN请求,完成剩下的两次挥手。

四次挥手后客户端维护的连接就会进入到TIME_WAIT状态,而服务器维护的连接则会立马进入到CLOSED状态。

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

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

相关文章

LeetCode - 1049 最后一块石头的重量 II (0-1背包)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/130935119 LeetCode:1049. 最后一块石头的重量 II 题目:有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选…

人脸识别3:C/C++ InsightFace实现人脸识别Face Recognition(含源码)

人脸识别3:C/C InsightFace实现人脸识别Face Recognition(含源码) 目录 1. 前言 2. 项目安装 (1)项目结构 (2)配置开发环境(OpenCVOpenCLbase-utilsTNN) (3)部署TNN模型 (4&a…

【C++】手把手教你模拟实现string类

模拟实现string 前言类的成员变量构造函数析构函数size和length[ ] 重载迭代器赋值运算符重载和拷贝构造函数拷贝构造函数赋值运算符重载现代式写法 reserve 和 resizereserveresize 字符串追加push_backappend insertpos位置插字符pos位置插字符串 erase>> 和 <<&…

Linux---用户权限(权限位、chowd、chown)

1. 权限位 序号1&#xff0c;表示文件、文件夹的权限控制信息 序号2&#xff0c;表示文件、文件夹所属用户 序号3&#xff0c;表示文件、文件夹所属用户组 权限细节总共分为10个槽位&#xff1a; 举例&#xff1a;drwxr-xr-x&#xff0c;表示&#xff1a; 这是一个文件夹&…

如何使用Metasploit进行后渗透攻击?

后渗透攻击&#xff08;PostExploitation&#xff09;是整个渗透测试过程中最能够体现渗透测试团队创造力与技术能力的环节。前面的环节可以说都是在按部就班地完成非常普遍的目标&#xff0c;而在这个环节中&#xff0c;需要渗透测试团队根据目标组织的业务经营模式、保护资产…

关于PyQt5的环境搭建

目录 一、需要的环境 二、安装python 1、python安装链接 三、安装PyQt5 1、使用豆瓣的镜像 2、配置环境变量 四、安装pycharm 1、pycharm官网链接 五、配置环境 1、找到设置 2、添加designer 3、配置ui 4、配置rc 六、注意问题 一、需要的环境 1、安装好python安装…

【Linux CAN应用编程(1)】初识CAN总线(附全文代码)

接下来我们学习 CAN 应用编程&#xff0c;CAN 是目前应用非常广泛的现场总线之一&#xff0c;主要应用于汽车电子和工业领域&#xff0c;尤其是汽车领域&#xff0c;汽车上大量的传感器与模块都是通过 CAN 总线连接起来的。CAN 总线目前是自动化领域发展的热点技术之一&#xf…

1、Vue简介与环境搭建

目录 一、Vue简介二、Vue开发环境1 - 环境安装2 - 新建Vue项目3 - VS Code4 - Vue项目的目录结构 一、Vue简介 官方文档&#xff1a;https://cn.vuejs.orgVue的api风格&#xff1a;选项式 API&#xff08;Vue 2&#xff09; 和组合式 API&#xff08;Vue 3&#xff09;**选项式…

怎么把pdf转成word?转换途径一览

在日常生活和工作中&#xff0c;我们常常需要处理各种文档格式。其中&#xff0c;PDF 作为一种流行的跨平台文件格式&#xff0c;广泛应用于技术文档、报告、合同和电子书等领域。但是&#xff0c;当我们需要修改 PDF 文件内容时&#xff0c;却往往会遇到困难。这时&#xff0c…

JavaScript引擎,V8引擎的原理

为什么需要JavaScript引擎&#xff1f; 高级的编程语言都是需要转成最终的机器指令来执行 我们所编写的js无论h是交给浏览器或者node执行&#xff0c;最后都是需要被CPU执行的 CPU只认识自己的指令集&#xff08;机器语言&#xff09;才能被CPU所执行 所以我们需要js引擎帮助我…

掌握了它,软件测试拿下25K轻轻松松!

了解软件测试这行的人都清楚&#xff0c;功能测试的天花板可能也就15k左右&#xff0c;而自动化的起点就在15k左右&#xff0c;当然两个岗位需要掌握的技能肯定是不一样的。 如果刚入门学习完软件测试&#xff0c;那么基本薪资会在7-8k左右&#xff0c;这个薪资不太高主要是因…

JQuery - JavaScript 的框架 - 语法简化版本

目录 js文件与 script 标签的位置问题总结&#xff1a; 有的时候是很坑&#xff0c;看了挺多资料&#xff0c;有时候乱糟糟的&#xff0c;都不说清楚&#xff0c;这是JavaScript的语法&#xff0c;还是 JQuery的语法&#xff0c;所以就会因为没有导入 JQuery的js文件&#xff0…

「功能测试进阶到自动化测试」一路走来都离不每个阶段的计划

关于「从功能测试&#xff0c;转岗到自动化测试」&#xff0c;主要的几个问题 &#xff1a; 001 目前一直在走功能测试&#xff0c;工作中也没有机会接触自动化测试 。想后续从事自动化测试&#xff0c;我应该从哪里开始学 &#xff1f; 解答&#xff1a;自动化 &#xff0c…

【六】设计模式~~~结构型模式~~~适配器模式(Java)

【学习难度&#xff1a;★★☆☆☆&#xff0c;使用频率&#xff1a;★★★★☆】 1.1. 模式动机 在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式。通常情况下&#xff0c;客户端可以通过目标类的接口访问它所提供的服务。有时&#xff0c;现有的类可以满…

全渠道电子商务指南

希望将全渠道电子商务纳入您的业务战略&#xff0c;但不确定从哪里开始。这篇博文将指导您了解全渠道商务的基础知识&#xff0c;以及它与多渠道方法的区别。 全渠道电子商务旨在为线上和线下多个平台的客户创造全面的购物体验。客户可以通过各种接触点&#xff08;例如网站、…

网络安全-02-BurpSuite工具安装

网络安全-02-BurpSuite工具安装 &#x1f53b;一、BurpSuite简介&下载&#x1f4d7; 二、Windows安装Jdk&#x1f4f0; 2.1 下载Jdk并安装&#x1f4f0; 2.2 设置Jdk环境变量&#x1f4dc; 2.2.1 设置JAVA_HOME&#x1f4dc; 2.2.2 设置path&#x1f4dc; 2.2.3 Jdk验证 &a…

数据库基础——8.单行函数

这篇文章我们来讲一下数据库里面的单行函数 目录 1. 函数的理解 1.1 什么是函数 1.2 不同DBMS函数的差异 1.3 MySQL的内置函数及分类 2. 数值函数 2.1 基本函数 2.2 角度与弧度互换函数 2.3 三角函数 2.4 指数与对数 2.5 进制间的转换 3. 字符串函数 4. 日期和…

PyCharm配置Opencv

具体方案&#xff1a; Plan A&#xff1a;可以直接在pycharm中配置&#xff08;如果有梯子可以试试&#xff0c;没有可能下载不了&#xff09; 参考视频&#xff1a;直接在Pycharm中配置即可 两分钟用Pycharm安装并配置OpenCV_哔哩哔哩_bilibili PlanB&#xff1a;通过终端安…

dolphinscheduler3.1.7windows部署启动说明

简介 Apache DolphinScheduler是一个新一代分布式大数据工作流任务调度平台&#xff0c;致力于“解决大数据任务之间错综复杂的依赖关系&#xff0c;整个数据处理开箱即用”。它以 DAG(有向无环图) 的方式将任务连接起来&#xff0c;可实时监控任务的运行状态&#xff0c;同时…

01Redis单线程 VS 多线程

不同版本&#xff0c;情况不同 Redis的版本很多3.x、4.x、6.x&#xff0c;版本不同架构也是不同的&#xff0c;不限定版本问是否单线程也不太严谨。 版本3.x &#xff0c;最早版本&#xff0c;也就是大家口口相传的redis是单线程 数据结构简单避免锁的开销和上下文切换可以有…