【Linux网络】基于TCP的全连接队列与文件、套接字、内核之间的关系
W...Y的主页 😊
代码仓库管理💕
前言:之前我们已经学习了TCP传输协议,而无论是TCP还是UDP都是使用socket套接字进行网络传输的,而TCP的socket是比UDP复杂的,当时我们学习TCPsocket编程时使用listen函数进行监听,今天我们就来说说listen函数第二个参数的含义,并且打通socket与内核之间的关系!!
目录
理解 listen 的第二个参数
理解全连接队列
在内核中理解全连接队列与套接字
理解 listen 的第二个参数
基于刚才封装的 TcpSocket 实现以下测试代码。对于服务器, listen 的第二个参数设置为 1, 并且不调用 accept。不调用accept就无法建立连接,导致这些连接全部会在全连接队列中(全连接队列是什么我们会在后面讲述)。
test_server.cc
#include "tcp_socket.hpp"
int main(int argc, char* argv[]) {
if (argc != 3) {
printf("Usage ./test_server [ip] [port]\n");
return 1;
}
TcpSocket sock;
bool ret = sock.Bind(argv[1], atoi(argv[2]));
if (!ret) {
return 1;
}
ret = sock.Listen(2);
if (!ret) {
return 1;
}
// 客户端不进行 accept
while (1) {
sleep(1);
}
return 0;
}
test_client.cc
#include "tcp_socket.hpp"
int main(int argc, char* argv[]) {
if (argc != 3) {
printf("Usage ./test_client [ip] [port]\n");
return 1;
}
TcpSocket sock;
bool ret = sock.Connect(argv[1], atoi(argv[2]));
if (ret) {
printf("connect ok\n");
} else {
printf("connect failed\n");
}
while (1) {
sleep(1);
}
return 0;
}
此时启动 3 个客户端同时连接服务器, 用 netstat 查看服务器状态, 一切正常,但是启动第四个客户端时, 发现服务器对于第四个连接的状态存在问题了。
tcp 3 0 0.0.0.0:9090 0.0.0.0:*
LISTEN 9084/./test_server
tcp 0 0 127.0.0.1:9090 127.0.0.1:48178
SYN_RECV -
tcp 0 0 127.0.0.1:9090 127.0.0.1:48176
ESTABLISHED -
tcp 0 0 127.0.0.1:48178 127.0.0.1:9090
ESTABLISHED 9140/./test_client
tcp 0 0 127.0.0.1:48174 127.0.0.1:9090
ESTABLISHED 9087/./test_client
tcp 0 0 127.0.0.1:48176 127.0.0.1:9090
ESTABLISHED 9088/./test_client
tcp 0 0 127.0.0.1:48172 127.0.0.1:9090
ESTABLISHED 9086/./test_client
tcp 0 0 127.0.0.1:9090 127.0.0.1:48174
ESTABLISHED -
tcp 0 0 127.0.0.1:9090 127.0.0.1:48172
ESTABLISHED -
前三个连接状态都是established,而第四个连接的客户端的状态是syn_sent(链接同步发送状态)是没有连接成功的,三次握手都没有成功。往后所以的客户端想要连接都会是syn_sent状态。
所以我们得出结论:在服务器来不及accept时,底层的TCP listen socket允许用户进行三次握手建立成功连接,但是不能建立太多,最多能建立backlog + 1个连接。 而这个backlog就是listen函数的第二个参数。
我们将这些建立好连接的链接会放在一个队列来维护,这个队列就是全连接队列。
客户端状态正常, 但是服务器端出现了 SYN_RECV 状态, 而不是 ESTABLISHED 状态这是因为, Linux 内核协议栈为一个 tcp 连接管理使用两个队列:
1. 半链接队列(用来保存处于 SYN_SENT 和 SYN_RECV 状态的请求)
2. 全连接队列(accpetd 队列)(用来保存处于 established 状态,但是应用层没有调用 accept 取走的请求)
而全连接队列的长度会受到 listen 第二个参数的影响.
全连接队列满了的时候, 就无法继续让当前连接的状态进入 established 状态了.
这个队列的长度通过上述实验可知, 是 listen 的第二个参数 + 1.
理解全连接队列
连接本质是内核中的一种数据结构,而我们使用socket套接字中的accept就是为了将已经建立好的连接拿上来进行使用。accpet函数在建立连接的同时,还能获取客户端的地址和端口信息。
我们不能将backlog中参数和服务器只能处理backlog+1个连接所混淆,服务器可以处理多个请求,这些连接就会被拿到上层不再全连接队列中,而全连接队列中的连接是已经建立好三次握手连接的却来不及接收的连接!!!
而我们不能不要这个全连接队列,因为这个全连接队列就相当于一个缓冲区,这个模式就是生产消费者模型,如果服务端突然空闲那就可以连接全连接队列中的连接,提高了整个服务端的吞吐量和用户的体验。如果没有全连接队列就会增加服务端的闲置率!
我们也不能设置太长,如果设置太长那么晚来的客户端就在队列的尾部也会等很长时间,许多用户等不住就会关掉连接,但是还没有达到最终目的浪费了用户时间并且浪费服务器维护队列空间。
在内核中理解全连接队列与套接字
在Linux内核中,task_struct结构体是描述进程的核心数据结构,它包含了控制和管理进程所必需的全部信息。 而struct file_struct结构体是用啦维护文件描述符的一个数据结构,他记录了一个进程打开的所有文件消息,file_struct中有一个fd数组用来记录文件描述符的。
在Linux内核中,struct file
结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file
实例。
所以使用listen_socket打开一个文件,就有一个文件描述符指向打开的struck file中,这时我们所理解的。
而我们使用socket创建套接字时,内核就为我们创建了一个struct socket结构体,struct file 与struct socket用*private_data指针关联,上图就是我们结构体的内容。struct socket结构体就是我们网络的入口。
但真实的情况是创建一个TCP连接,而真正的应该是一个tcp_sock的结构体。而tcp是面向连接的,里面有一个字段也是一个结构体是struct inet_connection_sock,他说tcp_sock中第一个字段,这个结构体包含了tcp链接的相关消息(超时时间……),里面有个字段是struct request_sock_queue icsk_accept_queue,这个就是全连接队列。而struct inet_connection_sock中第一个字段又是一个结构体struct inet_sock(里面有源端口、目的端口、源IP、目的IP……)而struct inet_sock里面第一个字段又是一个结构体struct sock
而我们的struct socket结构体中有一个字段struct sock* sk指针,这个指针就可以指向struct tcp_sock结构体并且使用强转就可以对tcp_sock里面的所有字段进行访问。这就是C风格的多态。
而我们的UDP与TCP大相径庭,只不过UDP是无连接的,所以在udp_sock中没有struct inet_connection_sock字段,剩下都是一样的。
我们的struct socket中有一个字段struct proto_ops结构体指针,里面存放了UDP与TCP的函数方法集。所以我们的struct socket是基类,tcp_sock与udp_sock都是子类。我们把struct socket叫做BSD socket——通用socket接口,把子类叫做inet_sock
上述是我们讲述的创建一个listen套接字,而如何获取一个连接呢(accept)?
当我们进行三次握手成功后就会建立tcp_sock结构体,这个结构体会被连入全连接队列中,后面我们进行accept时就会创建struct file 然后再创建struct socket,之后将struct file 与struct socket用*private_data指针关联起来并在文件描述符表中申请一个fd(这些操作都是由一个函数(映射)完成的(sock_map_fd)),然后就会再全连接队列中获取tcp_sock结构体进行关联,直接用struct socket中的sock指针指向tcp_sock结构体,这样我们的一个普通套接字也有上述对应的结构了。
这就是在内核中socket、UDP、TCP、全连接队列、文件所对应的关系,下面我们用一张非常简单的图来表示对应关系:
详细可以参考源码,此处不展示!!!
相关文章:

【Linux网络】基于TCP的全连接队列与文件、套接字、内核之间的关系
W...Y的主页 😊 代码仓库管理💕 前言:之前我们已经学习了TCP传输协议,而无论是TCP还是UDP都是使用socket套接字进行网络传输的,而TCP的socket是比UDP复杂的,当时我们学习TCPsocket编程时使用listen函数进行…...
IDE(集成开发环境)
IDE(集成开发环境)是软件开发过程中不可或缺的工具,它集成了代码编写功能、分析功能、编译器、调试器等开发工具,旨在提高开发效率。不同的IDE支持不同的语言和框架,下面是一些通用的IDE使用技巧和插件推荐,…...

一键导入Excel到阿里云PolarDB-MySQL版
今天,我将分享如何一键导入Excel到阿里云PolarDB-MySQL版数据库。 准备数据 这里,我们准备了一张excel表格如下: 连接到阿里云PolarDB 打开的卢导表,点击新建连接-选择阿里云PolarDB-MySQL版。如果你还没有这个工具,…...
Oracle有哪些版本
目录 Oracle 1(1979年) Oracle 2(1983年) Oracle 7(1992年) Oracle 8i(1999年) Oracle 9i(2001年) Oracle 10g(2004年) Oracle 11g(2007年) Oracle 12c(2013年) Oracle 18c(2018年) Oracle 19c(2019年) Oracle 21c(2023年) Oracle 23ai(202…...
先来先服务(FCFS,First-Come, First-Served)调度算法
有利于CPU繁忙作业的原因 充分利用CPU资源: 当一个CPU繁忙型的作业到达后,它会立即被执行,并且在没有其他作业等待的情况下,可以一直占用CPU直到完成。这使得CPU能够持续地执行作业,最大化利用CPU资源。 减少上下文切换…...
Windows操作系统忘记密码怎么办 这个方法屡试不爽 还不来试一下
Windows操作系统重置密码的操作步骤如下: 本方法适用于Windows Server 2008R2及其之后的操作系统。 第一步:从Windows 2008R2之后的操作系统光盘启动到安装界面,一直下一步到磁盘分区界面,按shiftF10调出cmd命令行界面。 第二步&…...

基于java的山区环境监督管理系统(源码+定制+开发)环境数据可视化、环境数据监测、 环境保护管理 、污染防治监测系统 大数据分析
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...
jQuery Mobile 表单输入
jQuery Mobile 表单输入 引言 在移动设备上,表单输入是用户与移动应用交互的重要方式。jQuery Mobile 是一个基于 jQuery 的移动设备友好的开发框架,它提供了丰富的组件和工具来帮助开发者创建响应式和交互式的移动界面。本文将详细介绍如何使用 jQuery Mobile 来创建和定制…...

IoC详解
共有两类注解类型可以实现: 1. 类注解:Controller、Service、Repository、Component、Configuration. 2. 方法注解:Bean. 类注解 Controller(控制器存储) 使⽤Controller存储bean的代码如下所⽰: Con…...

基于 ThinkPHP+Mysql 灵活用工_灵活用工系统_灵活用工平台
基于 ThinkPHPMysql 灵活用工灵活用工平台灵活用工系统灵活用工小程序灵活用工源码灵活用工系统源码 开发语言 ThinkPHPMysql 源码合作 提供完整源代码 软件界面展示 一、企业管理后台 二、运用管理平台 三、手机端...
etcd之etcd分布式锁及事务(四)
1、etcd分布式锁及事务 1.1 前言 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如 果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要…...

智慧旅游微信小程序平台
作者介绍:✌️大厂全栈码农|毕设实战开发,专注于大学生项目实战开发、讲解和毕业答疑辅导。 🍅获取源码联系方式请查看文末🍅 推荐订阅精彩专栏 👇🏻 避免错过下次更新 Springboot项目精选实战案例 更多项目…...

C++设计模式创建型模式———简单工厂模式、工厂方法模式、抽象工厂模式
文章目录 一、引言二、简单工厂模式三、工厂方法模式三、抽象工厂模式四、总结 一、引言 创建一个类对象的传统方式是使用关键字new , 因为用 new 创建的类对象是一个堆对象,可以实现多态。工厂模式通过把创建对象的代码包装起来,实现创建对…...

C++ 类与对象(中) 默认成员函数
我们知道在类中,有成员变量和成员函数,我们可以通过创造不同的成员函数来实现这个类不同的功能,如果我们创造一个类,却不实现它的成员函数会如何呢?这个就涉及到类中的默认成员函数的概念了。但在本文我们主要介绍以下…...
中间人攻击(https降级攻击)和iptables命令分析
中间人攻击 以下是一个简单的中间人攻击示例,结合 ARP 欺骗和流量修改: 1. 进行 ARP 欺骗 首先,使用 arpspoof 进行 ARP 欺骗,将受害者的流量重定向到攻击者的机器上: sudo arpspoof -i eth0 -t 172.29.144.50 172…...
开源生活-分布式管理
开源竞争(当自己没有办法彻底掌握一门技术的时候就彻底开源掉;培养出更多的依赖,让更多人帮助你完善你的技术,那么这不就是在砸罐子吗?一个行业里面总会有人先砸罐子的,你不如先砸罐子,还能听个…...
华为OD机试真题- 关联子串
该专栏题目包含两部分: 100 分值部分题目 200 分值部分题目 所有题目都会陆续更新,订阅防丢失 题目描述: 给定两个字符串str1和str2,如果字符串str1中的字符,经过排列组合后的字符串中,只要有一个字符串是…...

云智慧完成华为原生鸿蒙系统的适配, 透视宝 APM 为用户体验保驾护航
2024 年 10 月 22 日,首个国产移动操作系统 —— 华为原生鸿蒙操作系统 HarmonyOS NEXT 正式面世,成为继 iOS 和 Android 后的全球第三大移动操作系统。HarmonyOS NEXT,从系统内核、数据库根基,到编程语言创新、AI(人工…...

QT 多语言转换 ts、qm
QT开发之路 企业级开发系列文章,主要目标快速学习、完善、提升 相关技能 高效完成企业级项目开发 分享在企业中积累的实用技能和经验。 通过具体的编码过程、代码示例、步骤详解、核心内容和展示的方法解决遇到的实际问题。 阅读前声明 本系列文章属于付费内容 禁止…...
C++学习:类和对象(二)
一、默认成员函数 1. 什么是默认成员函数? 在C中,每个类都有一些特殊的成员函数,如果程序员没有显式地声明,编译器会自动为类生成这些函数,这些函数称为默认成员函数 2. 默认成员函数列表 默认构造函数(…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...