【网络】【Linux】Linux内核中连接的组织形式与全连接队列

news2024/11/23 4:00:58
Linux内核中连接的组织形式与全连接队列

文章目录

  • 1.前言
  • 2.Linux内核中连接的组织形式
    • 2.1套接字和文件描述符
    • 2.2创建连接 & 获取连接
  • 3.全连接队列
    • 3.1为什么有全连接队列?
    • 3.2全连接队列的长度

1.前言

TCP是面向连接的,TCP的各种可靠性机制实际都不是从主机到主机的,而是基于连接的。

比如一台服务器启动后可能有多个客户端前来访问,如果TCP不是基于连接的,也就意味着服务器端只有一个接收缓冲区,此时各个客户端发来的数据都会拷贝到这个接收缓冲区当中,此时这些数据就可能会互相干扰。

而我们在进行TCP通信之前需要先建立连接,就是因为TCP的各种可靠性保证都是基于连接的,要保证传输数据的可靠性的前提就是先建立好连接。

而一台机器上可能会存在大量的连接,此时操作系统就不得不对这些连接进行管理。

  • 操作系统在管理这些连接时需要“先描述,再组织”,在操作系统中一定有一个描述连接的结构体,该结构体当中包含了连接的各种属性字段,所有定义出来的连接结构体最终都会以某种数据结构组织起来,此时操作系统对连接的管理就变成了对该数据结构的增删查改。
  • 建立连接,实际就是在操作系统中用该结构体定义一个结构体变量,然后填充连接的各种属性字段,最后将其插入到管理连接的数据结构当中即可。
  • 断开连接,实际就是将某个连接从管理连接的数据结构当中删除,释放该连接曾经占用的各种资源。

以上都是理论层次的理解,那我们今天就具体地探究Linux源码中连接是如何组织起来的:

2.Linux内核中连接的组织形式

2.1套接字和文件描述符

网络通信本质上也是IO的过程,而且之前我们也说过调用send、recv等函数本质上是向Tcp维护的发送缓冲区、接收缓冲区写入和读出数据,既然是IO操作,所以一个套接字的本质其实就是一个文件描述符对应的文件。Linux下一切皆文件。

一个服务器本质上就是一个进程,而进程到文件的关系我们早已经在系统部分学习过:

QQ_1722932338139

当我们创建套接字时,Linux系统还会为我们创建一个新的结构体对象struct socket:

image-20240806162708417

我们观察到这个结构体内部包含了一个struct file类型的指针,该指针指向的就是该套接字对应的文件对象,所以我们此时可以通过该套接字找到对应的文件了,但是更重要的是我们需要通过文件描述符找到对应的套接字呢呀,现在只有一个单向的指针,即我现在需要从文件找到对应的套接字对象。

所以在struct file结构体中还包含一个指针:

QQ_1722932534072

这个指针指向的就是套接字socket结构,所以我们现在就可以通过该文件描述符完成对套接字的操作了(读取数据、获取连接等)。

2.2创建连接 & 获取连接

我们上面提到过连接本质上是内核中的一种数据结构,在Linux中实际就是struct tcp_sock结构体,该结构体专门用于TCP协议。

它包含了TCP协议特有的字段和方法,如TCP头部长度(tcp_header_len)、滑动窗口(rcv_wnd、snd_wnd)、拥塞控制算法相关字段(如srtt_us、mdev_us等)以及发送和接收队列等。

这个结构体是TCP连接在内核中的完整表示,包含了TCP协议运行所需的所有状态信息和控制逻辑。

struct tcp_sock结构体的第一个字段是struct inet_connection_sock结构体,该结构体增加了与连接管理相关的字段,如连接状态(icsk_state)、重传机制等。这个结构体为TCP连接提供了必要的状态管理和控制机制。

struct inet_connection_sock结构体的第一个字段是struct inet_sock结构体,该结构体增加了与IP层相关的字段和方法,如IP地址(sin_addr或sin6_addr)、端口号(sin_port或sin6_port)等。这个结构体为TCP和UDP等基于IP的协议提供了更具体的支持。

struct inet_sock结构体的第一个字段是struct sock结构体,该结构体包含了如套接字状态(state)、接收和发送缓冲区(sk_buff)队列、定时器(timer)等通用字段。

更重要的是你会发现与文件描述符相关的struct socket结构体中有一个字段就是struct sock类型的指针 sk:

QQ_1722935179811

所以socket套接字可以通过这个 sk指针 获取tcp_sock结构体中的所有字段内容(通过类型转换)。

比如想要获取tcp_sock结构体中inet_connection_sock结构体中的字段内容,就可以将sk指针转换成 inet_connection_sock类型获取。

这种通过一个指针获取不同结构体中属性的方式被称为“C风格的多态”。

QQ_1722936724152

以上是Tcp连接,如果是Udp连接呢?我们说Udp是无连接的通信协议,所以对于Udp来说没有struct inet_connection_sock结构体,因为该结构体内部维护的是与连接管理的相关字段,但是同样的根据socket结构体中的 sk指针 指向udp_sock结构体来获取udp连接的各种属性内容。所以 该socket结构体 被称为 “BSD socket ”— 通用socket接口。

既然socket结构体既可以指向Tcp套接字又可以指向Udp套接字,那是如何区分不同套接字类型的呢?

int socket(int domain, int type, int protocol);

参数type对应着socket结构体中的type字段:

QQ_1722937314330

所以创建一个listen套接字的流程就是申请文件描述符获得文件结构体,创建套接字socket和连接tcp_sock,然后将他们关联起来。

那么调用accept()函数是从listen套接字监听的套接字中获取普通连接并返回,这个过程又是怎样的呢?

实际上在struct inet_connection_sock结构体中维护一个全连接队列,当经历过三次握手后,系统会自动创建一个连接tcp_sock,然后将该连接加入到全连接队列中,当调用accept()函数时,操作系统会申请新的文件描述符和套接字socket,然后从全连接队列中取出一个连接tcp_sock,之后普通套接字socket中的 sk指针 指向该连接tcp_sock,就完成了获取连接的操作。

3.全连接队列

实际TCP在进行连接管理时会用到两个连接队列:

  • 全连接队列(accept队列)。全连接队列用于保存处于ESTABLISHED状态,但没有被上层调用accept取走的连接。
  • 半连接队列。半连接队列用于保存处于SYN_SENT和SYN_RCVD状态的连接,也就是还未完成三次握手的连接,维护时间比较短。

而全连接队列的长度实际会受到listen第二个参数的影响,一般TCP全连接队列的长度就等于listen第二个参数backlog的值加一。

int listen(int sockfd, int backlog);

如果将listen的第二个参数值设置为3,此时服务器端最多就允许存在4个处于ESTABLISHED状态的连接。

在服务器端已经有4个ESTABLISHED状态的连接的情况下,再有客户端发来建立连接请求,此时服务器端就会新增状态为SYN_RCVD的连接,该连接实际就是放在半连接队列当中的。

3.1为什么有全连接队列?

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

服务器端启动时一般会预先创建多个服务线程为客户端提供服务,主线程从底层accept上来连接后就可以将其交给这些服务线程进行处理。

如果向服务器发起连接请求的客户端很少,那么连接一旦在底层建立好就被主线程立马accept上来并交给服务线程处理了。

但如果向服务器发起连接请求的客户端非常多并且业务处理非常繁忙,即当每个服务线程都在为某个连接提供服务时,底层再建立好连接主线程就不能获取上来了,此时底层这些已经建立好的连接就会被放到连接队列当中,只有等某个服务线程空闲时,主线程就会从这个连接队列当中获取建立好的连接。

如果没有这个连接队列,那么当服务器端的服务线程都在提供服务时,其他客户端发来的连接请求就会直接被拒绝。

但有可能正当这个连接请求被拒绝时,某个服务线程提供服务完毕,此时这个服务线程就无法立马得到一个连接为之提供服务,所以一定有一段时间内这个服务线程是处于闲置状态的,直到再有客户端发来连接请求。

而如果设置了连接队列,当某个服务线程提供完服务后,如果连接队列当中有建立好的连接,那么主线程就可以立马从连接队列当中获取一个连接交给该服务线程进行处理,此时就可以保证服务器几乎是满载工作的,降低了服务器的闲置率。

3.2全连接队列的长度

虽然维护连接队列能让服务器处于几乎满载工作的状态,但连接队列也不能设置得太长。

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

所以全连接队列要取一个合适的长度,系统一般设置为5。

全连接队列的长度=min(backlog,net.core.somaxconn)+1:

  • 用户层调用listen时传入的第二个参数backlog。
  • 系统变量net.core.somaxconn,在 Linux 系统中,这个值默认可能因不同的发行版和内核版本而异,但常见的默认值可能是 128。然而,对于高负载的服务器,特别是在处理大量并发连接时,这个默认值可能太低,导致新的连接被拒绝(因为监听队列已满)。

通过以下命令可以查看系统变量net.core.somaxconn的值。

sudo sysctl -a | grep net.core.somaxconn

QQ_1722941458379


Stay hungry, Stay foolish. —史蒂夫-乔布斯

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

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

相关文章

c++中的引用()及做返回值问题

传值返回: int Count1() {int n 0;n;return n; } int main() {int& r1 Count1();return 0; } 总结:返回局部变量的引用是不安全的。 static int cab; 只有第一次定义c时才会执行 要想给变c的值应 static int c1; cab; 传值、传引用效率比较 #…

【抓包】- Fiddler抓包教程,使用Fiddle抓取B站视频;ffmpeg的使用方法

一、预准备:过滤器设置 打开fiddler后,清空内容,然后播放视频。 找到与B站视频资源相关的回应,而后在“原始(raw)”标签中查看它的host信息。 发现B站视频资源的服务器DNS地址为【*bilivideo.cn】、【*bi…

超越GPT-4 ,金融分析新突破:FinTral多模态大模型

人工智能咨询培训老师叶梓 转载标明出处 在金融领域,对大量非结构化数据的处理和分析一直是行业面临的重要挑战。为了解决这一问题,由不列颠哥伦比亚大学和Invertible AI的研究团队共同提出了一套名为FinTral的先进多模态大模型(LLMs&#xf…

云计算实训26——部署LVS负载均衡项目(上)

LVS LVS是linux virtural server的简称——免费、开源、四层负载均衡 工作原理: 通过linux达到负载均衡好和linux操作系统实现高性能高可用的linux服务集群,具有良好的可靠性、可扩展性、可操作性、可扩展性、从而实现以低廉的成本实现最优的性能。LV…

前端案例:Alloy Team|腾讯全端项目(响应式)

前言 这是一个简单的响应式项目,模仿了Alloy Team|腾讯全端部分内容,模拟了可以适应不同类型的设备 项目总览 整体布局 屏幕大于1200px概况: 头部标签hover 轮播图 屏幕在小于992px概况 头部背景变色 固定 屏幕在小于992px概况 屏幕大于7…

基于YOLOv8的手部检测(1)- 手部数据集获取(数据集下载、数据清洗、处理与增强)

前言 在进行手部姿态估计、手势识别时,需要先检测出手的位置。本文对网上公开的手部数据集进行获取、清洗、处理与数据增强,用于YOLO等目标检测网络的训练。 1.手部检测数据集概览 1.1 HaGRID手势识别数据集 项目地址: https://github.com/…

[C++] STL (multi)map/(multi)set简介

标题:[C] STL (multi)map/(multi)set简介 水墨不写bug 目录 前言: 一、set简介 1.set简介 2.set的常见用法 二、map简介 1.map简介 2.map使用 三、multiset简介 1.multiset简介 2.multiset使用 四、multimap简介 1.multimap简介 2.multim…

DVWA-IDS测试(特殊版本)

起因 浏览DVWA历史更新记录发现有版本带有IDS插件,可以用于平时没有相关设备等场景演示用,所以开启本次测试。 下载 官方最新版本是移除了IDS插件,原因是“从不使用”,所以需要下载移除该插件之前的版本。 https://github.com/…

【QuikGraph】图算法之Prim最小生成树求解

介绍 最小生成树概念与算法介绍 QuikGraph的PrimMinimumSpanningTreeAlgorithm的API地址 示例 测试代码: using Microsoft.VisualStudio.TestTools.UnitTesting; using QuikGraph; using QuikGraph.Algorithms.MinimumSpanningTree; using QuikGraph.Algorithm…

【Python 滑块图片复原】将steam蒸汽平台混乱的滑块背景图复原

文章日期:2024.08.16 使用工具:Python 文章类型:复原steam蒸汽平台里的滑块图片 文章全程已做去敏处理!!! 【需要做的可联系我】 AES解密处理(直接解密即可)(crypto-js…

【ElementUI】el-table值相同时合并行

效果图&#xff1a; 大致思路&#xff1a;el-table里添加合并行或列的计算方法span-method <el-table :data"tableList" :span-method"objectSpanMethod"> // 在获取到列表数据tableData后调用此方法 handleTableData(tableData) {let rowSpanArr …

探索JUnit源码:揭秘编程高手的秘密武器

摘要 本文将带领读者深入探索JUnit测试框架的源码&#xff0c;揭示其中蕴含的编程智慧和技巧。通过分析JUnit的实现原理&#xff0c;我们将学习到如何编写高质量、可维护的代码&#xff0c;并掌握一些高级编程技巧。 引言 在软件开发的世界里&#xff0c;测试是保证代码质量…

使用electron-vite创建桌面应用

使用electron-vite创建桌面应用 一、框架搭建二、项目目录三、preload.js解读 一、框架搭建 官网地址https://cn.electron-vite.org npm create quick-start/electronlatest按步骤操作即可 二、项目目录 1、main 主进程窗口&#xff1a;存放窗口代码 2、preload 预加载模块…

项目代码全自动国际化翻译工具

项目代码全自动国际化翻译工具 在当今全球化的时代&#xff0c;软件的国际化已不再是可选项&#xff0c;而是必需品。为了使软件能够覆盖更广泛的用户群体&#xff0c;支持多语言已成为每个开发团队的重要目标之一。然而&#xff0c;处理项目中的国际化问题并非易事&#xff0…

基于深度学习的图像特征优化识别复杂环境中的果蔬【多种模型切换】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍图像特征优化方法模型原理及实验对比模型训练每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 基于深度学习的图像识别技术广泛应…

企业发展与数字化转型:创新驱动未来增长的关键策略

引言 在当今全球化和信息化高度融合的时代&#xff0c;数字化转型已经成为企业寻求增长和保持竞争优势的关键战略。随着技术的飞速进步&#xff0c;数字化不仅改变了商业模式和市场格局&#xff0c;还深刻影响了企业的内部运作和外部生态系统。大数据、人工智能、物联网等新兴技…

【免费】企业级大模型应用推荐:星环科技无涯·问知

无涯问知是星环科技发布的大模型应用系统&#xff0c;那么我们先简单了解下星环科技吧&#xff01; 星环科技&#xff08;股票代码&#xff1a;688031&#xff09;致力于打造企业级大数据和人工智能基础软件&#xff0c;围绕数据的集成、存储、治理、建模、分析、挖掘和流通等数…

【保姆级教程】用pycharm连接远程数据库,并用sql语句进行增添语句

1.远程连接 检查是否连接成功 然后就能连接成功了。 2.可视化 双击&#xff0c;即可查看该表&#xff0c;左侧应该显示详细信息&#xff0c;类似navicat 3.增删改查&#xff08;前提&#xff1a;你有权限&#xff09; 3.1.非语句版 双击进行修改 点击箭头保存提交 3.2 sql语…

4.2 数据定义语言(DDL)

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…