I/O复用函数的使用——select
I/O复用函数的使用——select
目录
一、概念
二、select接口
2.1 基础概念
2.2 使用 select 函数的标准输入读取代码
2.3 基于 `select` 模型的多客户端 TCP 服务器实现
一、概念
i/o复用使得程序能同时监听多个文件描述符,可以提高程序性能。

之前为了让服务器能够服务多个客户端,我们使用多线程或多进程进行服务器的并发,意味着有多少个客户端就要产生很多进程。会浪费,开销很大。所以我们引入i/o复用
i/o复用方法select,poll,epoll可以帮助应用程序找到就绪描述符eg:老师检查作业,谁写完了谁举手,老师过去检查,不用一个一个等待去检查
二、select接口
2.1 基础概念
检测键盘是否有数据输入,如果有打印输出,没有就阻塞。select系统调用的用途是在一段指定时间内,监听用户感兴趣的文件描述符的可读,可写异常事件。
系统调用原型
#include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds:需要监视的文件描述符的最大值加1(fd + 1),因为文件描述符是从0开始的
readfds、writefds、exceptfds:分别表示可读、可写和异常条件的文件描述符集合,程序调用select函数时,通过这三个参数传入自己感兴趣的文件描述符。
timeout:超时时间,可以是NULL(阻塞等待),或者指定超时时间(非阻塞等待)。成功时,返回就绪文件描述符的总数,超时没有任何描述符就绪则返回0,失败返回-1,如果在等待期间,程序收到信号则立即返回-1并设置error为EINTR
fd_set:结构体,fd_mask,数组类型,fd_bits,数组名。用于存储和管理一组文件描述符 fd_set可以容纳1024个位 数组收集 描述符,把数组中的描述符添加到集合fd_set
fd_set结构体仅包含一个整型数组,该数组的每个元素的每一位bit标记一个文件描述符。fd_set能容纳的文件描述符数量由FD_SETSIZE指定,这就限制了select能同时处理的文件描述符的总量
由于位操作过于频繁,可以用一系列宏来访问fd_set结构体中的位
使用I/O复用技术(如
select、poll或epoll)来处理多个文件描述符(FD)的流程图

假设只有3和7上有数据,结构体集合经过select返回值为2,之后会测试和集合作比较看看对于的位是不是1,找到看哪个上面有数据
2.2 使用 select 函数的标准输入读取代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <time.h>#define STDIN 0 // 定义STDIN常量,表示标准输入的文件描述符int main()
{int fd = STDIN; // 将文件描述符fd初始化为标准输入fd_set fdset; // 定义一个文件描述符集合fdsetwhile (1) // 无限循环,持续等待输入{FD_ZERO(&fdset); // 清空文件描述符集合fdsetFD_SET(fd, &fdset); // 将标准输入的文件描述符添加到集合fdset中struct timeval tv = {5, 0}; // 定义一个timeval结构体,设置超时时间为5秒int n = select(fd+1, &fdset, NULL, NULL, &tv); // 调用select函数,监视fdset集合中的文件描述符if (-1 == n) // 如果select返回-1,表示发生错误{printf("select err\n"); // 打印错误信息continue; // 继续下一次循环}else if (n == 0) // 如果select返回0,表示超时,没有文件描述符就绪{printf("time out\n"); // 打印超时信息}else // 如果select返回大于0的值,表示有文件描述符就绪{if (FD_ISSET(fd, &fdset)) // 检查标准输入的文件描述符是否就绪{char buff[128] = {0}; // 定义一个字符数组buff,用于存储读取的数据read(fd, buff, 127); // 从标准输入读取数据到buff中,最多读取127个字符printf("read:%s\n", buff); // 打印读取到的数据}}}return 0; // 程序正常结束
}
这段代码使用
select函数来监视标准输入(键盘输入),并在有输入时读取数据。它首先定义了一个文件描述符集合fdset,并将标准输入的文件描述符添加到这个集合中。然后,它调用select函数来监视这个集合中的文件描述符,等待最多5秒。如果在这5秒内有任何文件描述符就绪(即有输入),select函数会返回就绪的文件描述符的数量。程序然后检查标准输入的文件描述符是否就绪,并从标准输入读取数据。如果5秒内没有文件描述符就绪,select函数会返回0,程序会打印超时信息。如果select函数返回-1,表示发生错误,程序会打印错误信息并继续下一次循环。if (FD_ISSET(fd, &fdset))
FD_ISSET是一个宏,用于检查一个特定的文件描述符(FD)是否已经包含在文件描述符集合(fd_set)中。这个宏是在使用select函数后,用来确定哪些文件描述符已经准备好进行 I/O 操作(如读、写)的常用方法。struct timeval tv = {5, 0}; // 定义一个timeval结构体,设置超时时间为5秒
struct timeval tv = {5, 0};:定义了一个timeval结构体变量tv,并初始化它。
timeval结构体:在Linux中,timeval结构体用于表示时间值,它包含两个字段:
tv_sec:表示时间的秒数部分。
tv_usec:表示时间的微秒数部分。初始化:这里将
tv_sec初始化为5,tv_usec初始化为0。这意味着超时时间为5秒。
2.3 基于 `select` 模型的多客户端 TCP 服务器实现
select.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>#define MAXFD 10 // 定义最大文件描述符数量// 初始化文件描述符数组
void fds_init(int fds[])
{for (int i = 0; i < MAXFD; i++){fds[i] = -1; // 将所有元素初始化为-1,表示未使用}
}// 向文件描述符数组添加一个文件描述符
void fds_add(int fds[], int fd)
{for (int i = 0; i < MAXFD; i++){if (-1 == fds[i]){fds[i] = fd; // 找到空位,添加文件描述符break; // 添加成功后退出循环}}
}// 从文件描述符数组中删除一个文件描述符
void fds_del(int fds[], int fd)
{for (int i = 0; i < MAXFD; i++){if (fds[i] == fd){fds[i] = -1; // 找到文件描述符,将其删除break; // 删除成功后退出循环}}
}// 初始化套接字
int socket_init()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建一个IPv4 TCP套接字if (sockfd == -1){return -1; // 创建失败,返回-1}struct sockaddr_in saddr; // 定义一个sockaddr_in结构体,用于存储服务器地址信息memset(&saddr, 0, sizeof(saddr)); // 将结构体清零saddr.sin_family = AF_INET; // 设置地址族为IPv4saddr.sin_port = htons(6000); // 设置端口号为6000,并转换为网络字节序saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置IP地址为127.0.0.1int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)); // 绑定套接字到本地地址if (-1 == res){printf("bind err\n"); // 绑定失败,打印错误信息return -1; // 返回-1}res = listen(sockfd, 5); // 开始监听连接请求,最多允许5个连接请求排队if (res == -1){return -1; // 监听失败,返回-1}return sockfd; // 返回监听套接字的文件描述符
}// 接受客户端连接请求
void accept_client(int sockfd, int fds[])
{int c = accept(sockfd, NULL, NULL); // 接受一个连接请求if (c < 0){return; // 接受失败,直接返回}printf("accept c=%d\n", c); // 打印接受的客户端文件描述符fds_add(fds, c); // 将客户端文件描述符添加到数组
}// 接收数据
void recv_data(int c, int fds[])
{char buff[128] = {0}; // 定义一个缓冲区,用于存储接收的数据int n = recv(c, buff, 127, 0); // 从客户端接收数据if (n <= 0){close(c); // 关闭套接字fds_del(fds, c); // 从数组中删除客户端文件描述符printf("client close\n"); // 打印客户端关闭信息return; // 返回}printf("recv:%s\n", buff); // 打印接收到的数据send(c, "ok", 2, 0); // 向客户端发送确认信息
}int main()
{int fds[MAXFD]; // 定义一个文件描述符数组fds_init(fds); // 初始化文件描述符数组int sockfd = socket_init(); // 初始化套接字if (sockfd == -1){exit(1); // 初始化失败,退出程序}fds_add(fds, sockfd); // 将监听套接字的文件描述符添加到数组fd_set fdset; // 定义一个文件描述符集合while (1){FD_ZERO(&fdset); // 清空文件描述符集合int maxfd = -1; // 初始化最大文件描述符for (int i = 0; i < MAXFD; i++){if (fds[i] == -1){continue; // 跳过未使用的文件描述符}if (maxfd < fds[i]){maxfd = fds[i]; // 更新最大文件描述符}FD_SET(fds[i], &fdset); // 将文件描述符添加到集合}struct timeval tv = {5, 0}; // 设置超时时间为5秒int n = select(maxfd + 1, &fdset, NULL, NULL, &tv); // 调用select函数,监视文件描述符集合if (-1 == n){printf("select err\n"); // select失败,打印错误信息}else if (0 == n){printf("time out\n"); // 超时,打印超时信息}else{for (int i = 0; i < MAXFD; i++){if (-1 == fds[i]){continue; // 跳过未使用的文件描述符}if (FD_ISSET(fds[i], &fdset)) // 检查文件描述符是否有就绪事件{// 处理就绪的文件描述符if (fds[i] == sockfd){// 监听套接字就绪,接受客户端连接请求accept_client(sockfd, fds);}else{// 客户端套接字就绪,接收数据recv_data(fds[i], fds);}}}}}
}
1. **包含必要的头文件**:
- 引入标准输入输出、标准库、Unix 系统调用、字符串操作、套接字编程、IP 地址转换等相关的头文件。2. **定义常量**:
- 定义 `MAXFD` 常量,表示文件描述符数组的最大长度。3. **初始化文件描述符数组** (`fds_init` 函数):
- 遍历数组,将所有元素初始化为 `-1`,表示这些文件描述符当前未被使用。4. **添加文件描述符到数组** (`fds_add` 函数):
- 在数组中查找第一个 `-1` 值的位置,并将传入的文件描述符 `fd` 存储在该位置。5. **从数组中删除文件描述符** (`fds_del` 函数):
- 在数组中查找传入的文件描述符 `fd`,并将对应的元素设置为 `-1`。6. **初始化套接字** (`socket_init` 函数):
- 创建 TCP 套接字。
- 设置服务器地址结构体 `sockaddr_in`,包括 IP 地址和端口号。
- 绑定套接字到指定的 IP 地址和端口号。
- 使套接字开始监听连接请求。7. **接受客户端连接请求** (`accept_client` 函数):
- 使用 `accept` 函数接受一个新的客户端连接请求。
- 打印客户端文件描述符。
- 将客户端文件描述符添加到文件描述符数组中。8. **接收数据** (`recv_data` 函数):
- 从指定的客户端文件描述符接收数据。
- 如果接收到的数据长度小于等于0(表示客户端已关闭连接),则关闭套接字并从数组中删除对应的文件描述符。
- 打印接收到的数据,并给客户端发送确认信息。9. **主函数 (`main`)**:
- 初始化文件描述符数组。
- 调用 `socket_init` 函数初始化套接字,并将监听套接字的文件描述符添加到数组中。
- 进入一个无限循环,持续等待和处理事件:
- 清空 `fd_set` 结构体 `fdset`。
- 遍历文件描述符数组,将所有有效的文件描述符添加到 `fdset` 中,并更新 `maxfd` 变量。
- 设置超时时间。
- 调用 `select` 函数监视 `fdset` 中的文件描述符,等待最多5秒钟。
- 根据 `select` 的返回值处理错误、超时或就绪的文件描述符:
- 如果 `select` 返回 `-1`,表示发生错误,打印错误信息。
- 如果 `select` 返回 `0`,表示超时,打印超时信息。
- 如果 `select` 返回大于 `0` 的值,表示有文件描述符就绪,遍历文件描述符数组,检查哪些文件描述符有就绪事件,并进行相应的处理:
- 如果就绪的文件描述符是监听套接字,则调用 `accept_client` 函数接受新的客户端连接请求。
- 如果就绪的文件描述符是客户端套接字,则调用 `recv_data` 函数接收数据。通过这些步骤,服务器能够同时处理多个客户端连接请求和数据接收,实现高效的 I/O 复用。
这段代码实现了一个简单的TCP服务器,它使用
select函数来同时处理多个客户端连接请求和数据接收。服务器首先初始化一个监听套接字,并将其文件描述符添加到文件描述符数组中。然后,它进入一个无限循环,使用select函数监视文件描述符数组中的所有文件描述符。当有文件描述符就绪时,服务器会根据文件描述符的类型(监听套接字或客户端套接字)来处理相应的事件(接受连接请求或接收数据)。
cli.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>int main()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建一个IPv4 TCP套接字if (sockfd == -1) // 检查套接字创建是否成功{exit(1); // 如果失败,退出程序}struct sockaddr_in saddr; // 定义一个sockaddr_in结构体,用于存储服务器地址信息memset(&saddr, 0, sizeof(saddr)); // 将结构体清零saddr.sin_family = AF_INET; // 设置地址族为IPv4saddr.sin_port = htons(6000); // 设置端口号为6000,并转换为网络字节序saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置IP地址为127.0.0.1int res = connect(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)); // 连接到服务器if (res == -1) // 检查连接是否成功{printf("connect err\n"); // 如果失败,打印错误信息exit(1); // 退出程序}while (1) // 无限循环,持续发送和接收数据{printf("input\n"); // 提示用户输入char buff[128] = {0}; // 定义一个缓冲区,用于存储输入和接收的数据fgets(buff, 128, stdin); // 从标准输入读取一行数据if (strncmp(buff, "end", 3) == 0) // 检查是否输入了"end"命令{break; // 如果是,退出循环}send(sockfd, buff, strlen(buff) - 1, 0); // 发送数据到服务器,不包括换行符memset(buff, 0, 128); // 清空缓冲区recv(sockfd, buff, 127, 0); // 从服务器接收数据printf("read:%s\n", buff); // 打印接收到的数据}close(sockfd); // 关闭套接字exit(0); // 程序正常结束
}
这段代码实现了一个简单的TCP客户端,它连接到本地服务器(127.0.0.1:6000),并持续发送和接收数据。用户可以在命令行中输入数据,输入"end"命令时,程序会退出。
相关文章:
I/O复用函数的使用——select
I/O复用函数的使用——select 目录 一、概念 二、select接口 2.1 基础概念 2.2 使用 select 函数的标准输入读取代码 2.3 基于 select 模型的多客户端 TCP 服务器实现 一、概念 i/o复用使得程序能同时监听多个文件描述符,可以提高程序性能。 之前为了让服务器能…...
ubuntu20.04安装安装x11vnc服务基于gdm3或lightdm这两种主流的显示管理器。
前言:在服务端安装vnc服务,可以方便的远程操作服务器,而不用非要插上显示器才行。所以在服务器上安装vnc是很重要的。在ubuntu20中,默认的显示管理器已经变为gdm3,它可以带来与 GNOME 无缝衔接的体验,强调功…...
图像预处理-图像轮廓特征查找
其实就是外接轮廓,有了轮廓点就可以找到最上、最下、最左、最右的四个坐标(因为有xmin,xmax,ymin,ymax)。就可以绘制出矩形。 一.外接矩形 cv.boundingRect(轮廓点) - 返回x,y,w,h,传入一个轮廓的轮廓点,若有多个轮廓需…...
全同态加密医疗数据分析集python实现
目录 摘要一、前言二、全同态加密与医疗数据分析概述2.1 全同态加密(FHE)简介2.2 医疗数据分析需求三、数据生成与预处理四、系统架构与流程4.1 系统架构图五、核心数学公式六、异步任务调度与(可选)GPU 加速七、PyQt6 GUI 设计八、完整代码实现九、自查测试与总结十、展望…...
list的学习
list的介绍 list文档的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一…...
HarmonyOS:Navigation实现导航之页面设置和路由操作
导读 设置标题栏模式设置菜单栏设置工具栏路由操作页面跳转页面返回页面替换页面删除移动页面参数获取路由拦截 子页面页面显示类型页面生命周期页面监听和查询 页面转场关闭转场自定义转场共享元素转场 跨包动态路由系统路由表自定义路由表 示例代码 Navigation组件适用于模块…...
管道位移自动化监测方案
一、背景 管道系统在区域性地质沉降作用下易形成非均匀应力场集中现象,诱发管体屈曲变形及环焊缝界面剥离等连续损伤累积效应,进而导致管道力学性能退化与临界承载能力衰减。传统人工巡检受限于空间覆盖度不足及数据采集周期长(≥72h…...
AI之pdf解析:Tesseract、PaddleOCR、RapidPaddle(可能为 RapidOCR)和 plumberpdf 的对比分析及使用建议
目录标题 Tesseract、PaddleOCR、RapidPaddle(可能为 RapidOCR)和 plumberpdf 的对比分析1. Tesseract类型: 开源 OCR 引擎特点:缺点:适用场景: 2. PaddleOCR (推荐)类型:特点:缺点:适用场景: 复杂版式文档、多语言混合文本、需要高精度识别的场景&#…...
【学习笔记】机器学习(Machine Learning) | 第五周| 分类与逻辑回归
机器学习(Machine Learning) 简要声明 基于吴恩达教授(Andrew Ng)课程视频 BiliBili课程资源 文章目录 机器学习(Machine Learning)简要声明 一、逻辑回归的基本原理分类判断条件模型输出的解释Sigmoid 函数与 Logistic 函数逻辑…...
悬停以及点击切换图片
为了实现悬停切换图片的功能,我们可以为每个按钮添加鼠标悬停事件监听器。以下是详细步骤和代码: 首先在控制器类中添加初始化方法,并添加事件监听器: package com.example.demo6;import javafx.event.ActionEvent; import java…...
Python 深度学习 第8章 计算机视觉中的深度学习 - 卷积神经网络使用实例
Python 深度学习 第8章 计算机视觉中的深度学习 - 卷积神经网络使用实例 内容概要 第8章深入探讨了计算机视觉中的深度学习,特别是卷积神经网络(convnets)的应用。本章详细介绍了卷积层和池化层的工作原理、数据增强技术、预训练模型的特征…...
Python基础总结(九)之推导式
文章目录 一、列表推导式1.1 列表推导式的格式1.2 列表推导式的注意事项1.3 列表推导式示例 二、 字典推导式2.1 字典推导式格式2.2 字典推导式注意事项2.3 字典推导式示例 三、 元组推导式3.1 元组推导式格式3.3 元组推导式示例 Python中的推导式有列表推导式,字典…...
[免费]SpringBoot+Vue博物馆(预约)管理系统【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的SpringBootVue博物馆(预约)管理系统,分享下哈。 项目视频演示 【免费】SpringBootVue博物馆(预约)管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着计算机科学技术的日渐成熟ÿ…...
基于LangChain4J的AI Services实践:用声明式接口重构LLM应用开发
基于LangChain4J的AI Services实践:用声明式接口重构LLM应用开发 前言:当Java开发遇上LLM编程困境 在LLM应用开发领域,Java开发者常面临两大痛点:一是需要手动编排Prompt工程、记忆管理和结果解析等底层组件,二是复杂…...
制作一款打飞机游戏12:初稿原型
当前进展 任务回顾:在之前,我们做了大量的规划和原型设计。我们创建了关卡,添加了侧向滚动和BOSS模式背景重复,还制作了一个紧凑的瓦片集。原型完成:我们完成了五个原型,基本实现了飞机飞行、滚动…...
【python】pyCharm常用快捷键使用-(2)
pyCharm常用快捷键使用 快速导入任意类 【CTRLALTSPACE】代码补全【CTRLSHIFTENTER】代码快速修正【ALTENTER】代码调试快捷键...
位运算,状态压缩dp(算法竞赛进阶指南学习笔记)
目录 移位运算一些位运算的操作最短 Hamilton 路径(状态压缩dp模板,位运算) 0x是十六进制常数的开头;本身是声明进制,后面是对应具体的数; 数组初始化最大值时用0x3f赋值; 移位运算 左移 把二…...
极狐GitLab 项目 API 的速率限制如何设置?
极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 项目 API 的速率限制 (BASIC SELF) 引入于 15.10 版本,功能标志为rate_limit_for_unauthenticated_projects_api_…...
机器视觉lcd屏增光片贴合应用
在现代显示制造领域,LCD屏增光片贴合工艺堪称显示效果的"画龙点睛"之笔。作为提升屏幕亮度、均匀度和色彩表现的关键光学组件,增光片的贴合精度直接影响着终端用户的视觉体验。传统人工贴合方式难以满足当前超窄边框、高分辨率显示屏的严苛要求…...
VScode-py环境
settings.json {"git.ignoreLimitWarning": true,"code-runner.runInTerminal": true,"code-runner.executorMap": {"python": "python3"} } 第二句话保证在终端里面进行IO 第三句话保证python3的用户不会执行python关键…...
大模型面经 | 春招、秋招算法面试常考八股文附答案(三)
大家好,我是皮先生!! 今天给大家分享一些关于大模型面试常见的面试题,希望对大家的面试有所帮助。 往期回顾: 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题一) 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题二) 大模型面经 | 春招、秋招算法…...
用键盘实现控制小球上下移动——java的事件控制
本文分享Java的一个有趣小项目,实现用键盘控制小球的移动 涉及java知识点:Swing GUI框架,绘图机制,事件处理,焦点控制 1.编写窗口和面板 (1.)定义面板类 Panel 继承自Java 自带类JPanel (2.)定义窗口类 window 继承…...
《Relay IR的基石:expr.h 中的表达式类型系统剖析》
TVM Relay源码深度解读 文章目录 TVM Relay源码深度解读一 、从Constant看Relay表达式的设计哲学1. 类定义概述2. ConstantNode 详解1. 核心成员2. 关键方法3. 类型系统注册 3. Constant 详解1. 核心功能 二. 核心内容概述(1) Relay表达式基类1. RelayExprNode 和 RelayExpr 的…...
《马尼拉》桌游期望计算器
《马尼拉》桌游期望计算器:做出最明智的决策 注:本项目仍在开发验证中,计算结果可能不够准确,欢迎游戏爱好者提供协助! 在线使用 | GitHub 项目简介 马尼拉期望计算器是一个基于 Vue 3 Vite 开发的网页应用ÿ…...
23种设计模式-结构型模式之适配器模式(Java版本)
Java 适配器模式(Adapter Pattern)详解 🔌 什么是适配器模式? 适配器模式用于将一个类的接口转换成客户端所期望的另一种接口,让原本接口不兼容的类可以协同工作。 📦 就像插头转换器,让不同…...
动态LOD策略细节层级控制:根据视角距离动态简化远距量子态渲染
动态LOD策略在量子计算可视化中的优化实现 1. 细节层级控制:动态简化远距量子态渲染 在量子计算的可视化中,量子态通常表现为高维数据(如布洛赫球面或多量子比特纠缠态)。动态LOD(Level of Detail)策略通过以下方式优化渲染性能: 距离驱动的几何简化: 远距离渲染:当…...
算法 | 成长优化算法(Growth Optimizer,GO)原理,公式,应用,算法改进研究综述,matlab代码
===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 成长优化算法 一、算法原理二、核心公式三、应用领域四、算法改进研究五…...
线程池的介绍
目录 一、什么是线程池 二、线程池的详细内容 三、线程池的简化 一、什么是线程池 提到线程池,我们可能想到 常量池,可以先来说说常量池: 像是字符串常量,在Java程序最初构建的时候,就已经准备好了,等程…...
安恒安全渗透面试题
《网安面试指南》https://mp.weixin.qq.com/s/RIVYDmxI9g_TgGrpbdDKtA?token1860256701&langzh_CN 5000篇网安资料库https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247486065&idx2&snb30ade8200e842743339d428f414475e&chksmc0e4732df793fa3bf39…...
基于瑞芯微RK3576国产ARM八核2.2GHz A72 工业评估板——ROS2系统使用说明
前 言 本文主要介绍创龙科技TL3576-MiniEVM评估板演示基于Ubuntu的ROS系统(版本:ROS2 Foxy)使用说明,包括镜像编译、镜像替换,以及ROS系统测试的方法。适用开发环境如下。 Windows开发环境:Windows 10 64bit Linux虚拟机环境:VMware16.2.5、Ubuntu22.04.5 64bit U-B…...


