当前位置: 首页 > news >正文

【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使用技巧和插件推荐&#xff0c…...

一键导入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. 默认成员函数列表 默认构造函数&#xff08…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

七、数据库的完整性

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

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

英国云服务器上安装宝塔面板(BT Panel)

在英国云服务器上安装宝塔面板&#xff08;BT Panel&#xff09; 是完全可行的&#xff0c;尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎&#xff0c;虽然官方主要面向中国大陆…...

多模态大语言模型arxiv论文略读(110)

CoVLA: Comprehensive Vision-Language-Action Dataset for Autonomous Driving ➡️ 论文标题&#xff1a;CoVLA: Comprehensive Vision-Language-Action Dataset for Autonomous Driving ➡️ 论文作者&#xff1a;Hidehisa Arai, Keita Miwa, Kento Sasaki, Yu Yamaguchi, …...

CMake系统学习笔记

CMake系统学习笔记 基础操作 最基本的案例 // code #include <iostream>int main() {std::cout << "hello world " << std::endl;return 0; }// CMakeLists.txt cmake_minimum_required(VERSION 3.0)# 定义当前工程名称 project(demo)add_execu…...