【Linux网络】深入解析I/O多路转接 - Select
📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨
文章目录
- 🏳️🌈一、什么是select
- 🏳️🌈二、select 函数原型
- 🏳️🌈三、测试 timeout
- 3.1 SelectServer 类
- 3.1.1 基本结构
- 3.1.2 析构构造函数
- 3.1.3 Loop()
- 3.1.4 InitServer()
- 3.2 主函数
- 3.3 测试代码
- 🏳️🌈四、Handler 处理函数 - 版本一
- 🏳️🌈五、Handler 处理函数 - 版本二
- 5.1 基本结构
- 5.2 初始化函数
- 5.3 Loop() 函数
- 5.4 HandlerEvent(() 函数
- 5.5 PrintDebug()
- 5.6 测试
- 🏳️🌈六、Handler 处理函数 - 版本三
- 🏳️🌈七、select 的特点
- 👥总结
11111111
11111111
11111111
11111111
**** 11111111
🏳️🌈一、什么是select
系统提供select
函数来实现多路复用输入/输出模型
select
系统调用是用来让我们的程序监视多个文件描述符的状态变化的;- 程序会停在
select
这里等待,直到被监视的文件描述符有一个或多个发生了状态改变;
定位:只负责进行等,不进行拷贝!
作用:为了等待多个fd,等待fd上面的新事件就绪,通知程序员,事件已经就绪,可以进行IO拷贝了!
🏳️🌈二、select 函数原型
select 的函数原型如下:
#include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数
nfds
:这是一个整数值,指定要监控的文件描述符集合中最大文件描述符的值加1。这是因为文件描述符是从0开始编号的,所以nfds实际上是文件描述符集合中最大索引值加1。readfds
:指向一个 fd_set 结构体的指针,该结构体包含了所有需要监控是否有数据可读
的文件描述符。如果不需要监控读事件,可以传递 NULL。writefds
:指向一个 fd_set 结构体的指针,该结构体包含了所有需要监控是否有数据可写
的文件描述符。如果不需要监控写事件,可以传递 NULL。exceptfds
:指向一个 fd_set 结构体的指针,该结构体包含了所有需要监控是否出现异常条件
的文件描述符。如果不需要监控异常事件,可以传递 NULL。timeout
:指向一个 timeval 结构体的指针,用来设置 select()的等待时间。
参数 timeout 取值:
nullptr
:则表示 select()没有 timeout,select 将一直被阻塞,直到某个文件描述符上发生了事件;0
:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。特定的时间值
:如果在指定的时间段里没有事件发生,select 将超时返回。’
timeval 结构
- 描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件,发生则函数返回,返回值为 0。
struct timeval
{
#ifdef __USE_TIME_BITS64__time64_t tv_sec; /* Seconds. */__suseconds64_t tv_usec; /* Microseconds. */
#else__time_t tv_sec; /* Seconds. */__suseconds_t tv_usec; /* Microseconds. */
#endif
};
fd_set 结构
- fds_bits 或 __fds_bits:一个
__fd_mask
类型的数组,用于存储文件描述符的位掩码 - __fd_mask:通常是
unsigned long
,表示一个位掩码单元。每个单元可存储 __NFDBITS 个文件描述符状态(如 64 位系统为 64 位)。 - __FD_SETSIZE:定义
fd_set
支持的最大文件描述符数量(默认通常为 1024)。 - __NFDBITS :单个
__fd_mask
元素的位数(如sizeof(__fd_mask) * 8
)。
typedef struct {
#ifdef __USE_XOPEN__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
#else__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
#endif
} fd_set;
其实这个结构就是一个整数数组, 更严格的说, 是一个 “位图
”。使用位图中对应的位来表示要监视的文件描述符。
函数返回值
- 执行成功则返回文件描述词状态已改变的个数
- 如果返回 0 代表在描述词状态改变前已超过 timeout 时间,没有返回
- 当有错误发生时则返回-1,错误原因存于 errno,此时参数 readfds,writefds,exceptfds 和 timeout 的值变成不可预测。
错误值可能为:
EBADF
文件描述词为无效的或该文件已关闭EINTR
此调用被信号所中断EINVAL
参数 n 为负值。ENOMEM
核心内存不足
🏳️🌈三、测试 timeout
前面
timeout
参数分析出三种情况,下面编写代码进行基本的测试!
3.1 SelectServer 类
SelectServer类
的成员需要用到 端口号 和 套接字,成员函数暂时实现InitServer()
和Loop()
,此处的套接字使用前面封装的Socket类
3.1.1 基本结构
#pragma once#include <iostream>
#include "Socket.hpp"using namespace SocketModule;class SelectServer{public:SelectServer(uint16_t port);void InitServer();void Loop(); ~SelectServer();private:uint16_t _port;SockPtr _listensock;
};
3.1.2 析构构造函数
构造函数初始化端口号并根据端口号创建监听套接字对象,析构函数暂时不做处理!
SelectServer(uint16_t port): _port(port), _listensock(std::make_shared<TcpSocket>()) {_listensock->BuildListenSocket(_port);
}
~SelectServer();
3.1.3 Loop()
Loop()函数此处主要用来测试timeout,也是后序使用的轮询函数!
void Loop() {while (true) {// 临时fd_set rfds; // 清除 rfds 中相关的fd的位FD_ZERO(&rfds);FD_SET(_listensock->Sockfd(), &rfds);struct timeval timeout = {3, 0};int n =::select(_listensock->Sockfd() + 1, &rfds, NULL, NULL, &timeout);switch (n) {case 0:LOG(LogLevel::DEBUG) << "time out " << timeout.tv_sec << "s";break;case -1:LOG(LogLevel::ERROR) << "select error";break;default:LOG(LogLevel::INFO) << "haved event ready, " << n;break;}}
}
3.1.4 InitServer()
InitServer()函数暂时不用填写代码,保证主函数把代码跑过即可
3.2 主函数
输入端口号运行即可
int main(int argc, char* argv[]){if(!argc != 2){std::cerr << "Usage: " << argv[0] << " locak-port" << std::endl; }uint16_t port = std::stoi(argv[1]);std::unique_ptr<SelectServer> svr = std::make_unique<SelectServer>(port);svr->InitServer();svr->Loop();return 0;
}
3.3 测试代码
根据左边的日志,我们会发现平均每 3 s会弹出一次超时
我们修改一下监听的情况,每3s 监听一次,并且超时为 30s
LOG(LogLevel::INFO) << "haved event ready, " << n;
LOG(LogLevel::DEBUG) << "time out " << timeout.tv_sec << "." << timeout.tv_usec<< "s";
sleep(3);
我们使用 telnet 模拟访问服务端, 每 3s 弹出一次套接字已就绪的字样
🏳️🌈四、Handler 处理函数 - 版本一
timeout
参数测试成功之后,需要正式进入事件处理,select()
函数的返回值不是0或者1就表示事件已经就绪,此处需要处理任务!
我们这里不进行计时即 select最后一个参数设为 NULL
void Loop() {while (true) {fd_set rfds; // 清除 rfds 中相关的fd的位FD_ZERO(&rfds);FD_SET(_listensock->Sockfd(), &rfds);int n = ::select(_listensock->Sockfd() + 1, &rfds, nullptr, nullptr, nullptr);switch (n) {// case 0: 因为不会超时所有case 0 的情况不存在case -1:LOG(LogLevel::ERROR) << "select error";break;default:LOG(LogLevel::INFO) << "haved event ready, " << n;break;}}
}
HandlerEvent()
版本一进行正式的任务处理,如果fd在读文件描述符集合中则获取链接并且获取链接成功,打印调试日志,否则直接返回!
void HandlerEvent(fd_set& rfds) {if (FD_ISSET(_listensock->Sockfd(), &rfds)) {// 连接事件就绪,等价于读事件就绪InetAddr addr;int sockfd = _listensock->Accepter(&addr);if (sockfd > 0) {LOG(LogLevel::DEBUG)<< "get a new connection from " << addr.AddrStr().c_str()<< ", sockfd : " << sockfd;} elsereturn;}
}
这里还需要更改一下 socket.hpp 的 Accepter 函数,因为我们返回的是一个 int 类型
int Accepter(InetAddr* cli) override {struct sockaddr_in client;socklen_t clientlen = sizeof(client);// accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)// 返回一个新的套接字,该套接字与调用进程间接地建立了连接。int sockfd = ::accept(_sockfd, CONV(&client), &clientlen);if (sockfd < 0) {LOG(LogLevel::ERROR) << "accept socket error";return -1;}*cli = InetAddr(client);LOG(LogLevel::DEBUG) << "get a new connection from "<< cli->AddrStr().c_str() << ", sockfd : " << sockfd;return sockfd;
}
🏳️🌈五、Handler 处理函数 - 版本二
在轮询的过程中,可能会有fd是合法的,但是没有就绪,而这次执行完之后,读文件描述符集合会清空,可能会出现问题,因此需要增加一个数组(数组成员个数为fd_set集合的位数),来保存合法的fd!
5.1 基本结构
- 我们需要添加一个能够存储文件描述符的数组
- 同时要设置最大监听数量,以及默认描述符
class SelectServer {const static int gnum = sizeof(fd_set) * 8;const static int gdefaultfd = -1;private:uint16_t _port;SockPtr _listensock;// select要正常工作,需要借助一个辅助数组,来保存所有合法fdint fd_array[gnum];
};
—
5.2 初始化函数
- 这里需要初始化文件描述符数值中的所有文件描述符,并且要设置监听套接字
void InitServer() {for (int i = 0; i < gnum; ++i) {fd_array[i] = gdefaultfd;}fd_array[0] = _listensock->Sockfd();
}
5.3 Loop() 函数
Loop()函数主要分以下三步:
-
文件描述符初始化
-
合法的fd添加到rfds集合中
2.1. 更新出最大的fd的值 -
检查读条件是否就绪
void Loop() {while (true) {// 1. 文件描述符初始化fd_set rfds; // 清除 rfds 中相关的fd的位FD_ZERO(&rfds);int max_fd = gdefaultfd;// 2. 合法的 fd 添加到 rfds 集合中for (int i = 0; i < gnum; ++i) {if (fd_array[i] == gdefaultfd)continue;FD_SET(fd_array[i], &rfds);if (fd_array[i] > max_fd)max_fd = fd_array[i];}struct timeval timeout = {30, 0};// 3. 检查都条件是否就绪int n = ::select(max_fd + 1, &rfds, nullptr, nullptr, &timeout);switch (n) {case 0:LOG(LogLevel::DEBUG) << "time out " << timeout.tv_sec << "."<< timeout.tv_usec << "s";break;case -1:LOG(LogLevel::ERROR) << "select error";break;default:// 如果事件就绪,但是不做处理,select 就会一直通知,直到处理LOG(LogLevel::DEBUG) << "time remain " << timeout.tv_sec << "."<< timeout.tv_usec << "s";LOG(LogLevel::INFO) << "haved event ready, " << n;HandlerEvent(rfds);sleep(3);break;}}
}
5.4 HandlerEvent(() 函数
在执行HandlerEvent()函数之前,赋值数组中一定存在大量的fd就绪,可能是普通sockfd,也可能是listensockfd,此处主要分以下两步:
- 1、判断fd是否合法
- 2、判断fd是否就绪
- 2.1、就绪是listensockfd
- 2.1.1、获取链接
2.1.2、获取链接成功将新的fd添加到数组中
2.1.3、数组满了,不能添加,需关闭sockfd- 2.2、就绪是normal sockfd
- 2.2.1、直接读取fd中内容
void HandlerEvent(fd_set& rfds) {// version - 0// if(FD_ISSET(_listensock->Sockfd(), &rfds)){// // 连接事件就绪,等价于读事件就绪// InetAddr addr;// int sockfd = _listensock->Accepter(&addr);// if(sockfd > 0){// LOG(LogLevel::DEBUG) << "get a new connection from " <<// addr.AddrStr().c_str() << ", sockfd : " << sockfd;// } else return;// }// version - 1for (int i = 0; i < gnum; ++i) {// 1. 判断 fd 是否合法if (fd_array[i] == gdefaultfd)continue;// 2. 判断 fd 是否就绪if (FD_ISSET(fd_array[i], &rfds)) {// 判断是 listensocketif (_listensock->Sockfd() == fd_array[i]) {InetAddr client;int sockfd = _listensock->Accepter(&client);if (sockfd > 0) {LOG(LogLevel::INFO)<< "get a new connection from "<< client.AddrStr().c_str() << ", sockfd : " << sockfd;// 将获取成功的新的 fd 添加到 fd_array 中bool flag = false;for (int pos = 1; pos < gnum; ++pos) {if (fd_array[pos] == gdefaultfd) {flag = true;fd_array[pos] = sockfd;LOG(LogLevel::DEBUG)<< "add new sockfd " << sockfd<< " to fd_array[" << pos << "]";break;}if (!flag) {LOG(LogLevel::ERROR)<< "fd_array is full, can't add new sockfd "<< sockfd;::close(sockfd);}}}}// 判断是其他 socketelse {// 正常读写}}}
}
5.5 PrintDebug()
PrintDebug()
遍历辅助数组,将合法的文件描述符打印出来!
void PrintDebug() {std::cout << "fd list: ";for (int i = 0; i < gnum; ++i) {if (fd_array[i] == gdefaultfd)continue;std::cout << fd_array[i] << " ";}std::cout << std::endl;
}
5.6 测试
🏳️🌈六、Handler 处理函数 - 版本三
前面两个版本已经完成对监听套接字和普通套接字的测试,但是结构看起来还是没有那么清晰,这个版本使用函数进行进一步封装!
void HandlerEvent(fd_set& rfds) {// version - 0// if(FD_ISSET(_listensock->Sockfd(), &rfds)){// // 连接事件就绪,等价于读事件就绪// InetAddr addr;// int sockfd = _listensock->Accepter(&addr);// if(sockfd > 0){// LOG(LogLevel::DEBUG) << "get a new connection from " <<// addr.AddrStr().c_str() << ", sockfd : " << sockfd;// } else return;// }// version - 1for (int i = 0; i < gnum; ++i) {// 1. 判断 fd 是否合法if (fd_array[i] == gdefaultfd)continue;// 2. 判断 fd 是否就绪if (FD_ISSET(fd_array[i], &rfds)) {// 判断是 listensocketif (_listensock->Sockfd() == fd_array[i]) {HandlerNewConnection();}// 判断是其他 socketelse {// 正常读写HandlerIO(i);}}}
}
void HandlerNewConnection() {InetAddr client;int sockfd = _listensock->Accepter(&client);if (sockfd > 0) {LOG(LogLevel::INFO)<< "get a new connection from " << client.AddrStr().c_str()<< ", sockfd : " << sockfd;// 将获取成功的新的 fd 添加到 fd_array 中bool flag = false;for (int pos = 1; pos < gnum; ++pos) {if (fd_array[pos] == gdefaultfd) {flag = true;fd_array[pos] = sockfd;LOG(LogLevel::DEBUG) << "add new sockfd " << sockfd<< " to fd_array[" << pos << "]";break;}}if (!flag) {LOG(LogLevel::ERROR)<< "fd_array is full, can't add new sockfd " << sockfd;::close(sockfd);}}
}
void HandlerIO(int i) {char buffer[1024];ssize_t n = ::recv(fd_array[i], buffer, sizeof(buffer) - 1, 0);if (n > 0) {buffer[n] = 0;std::cout << "client say# " << buffer << std::endl;std::string content = "<html><body><h1>hello linux</h1></body></html>";std::string echo_str = "HTTP/1.0 200 OK\r\n";echo_str += "Content-Type: text/html\r\n";echo_str +="Content-Length: " + std::to_string(content.size()) + "\r\n\r\n";echo_str += content;::send(fd_array[i], echo_str.c_str(), echo_str.size(), 0);} else if (n == 0) { // 客户端关闭连接LOG(LogLevel::INFO)<< "client closed connection, sockfd: " << fd_array[i];::close(fd_array[i]);fd_array[i] = gdefaultfd; // 清理数组中的fd} else { // recv 错误(如连接重置)LOG(LogLevel::ERROR) << "recv error, sockfd: " << fd_array[i];::close(fd_array[i]);fd_array[i] = gdefaultfd;}
}
🏳️🌈七、select 的特点
优点
- 可监控的文件描述符个数取决于
sizeof(fd_set)
的值. 博主这边服务器上sizeof(fd_set)=128
,每 bit 表示一个文件描述符,则博主服务器上支持的最大文件描述符是 128*8=1024. - 将
fd
加入select
监控集的同时,还要再使用一个数据结构 array 保存放到 select监控集中的 fd,- 一是用于在 select 返回后,array 作为源数据和 fd_set 进行 FD_ISSET 判断。
- 二是 select 返回后会把以前加入的但并无事件发生的 fd 清空,则每次开始select 前都要重新从 array 取得 fd 逐一加入(FD_ZERO 最先),扫描 array 的同时取得 fd 最大值 maxfd,用于 select 的第一个参数。
缺点
- 每次调用 select, 都需要手动设置 fd 集合, 从接口使用角度来说也非常不便.
- 每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大(这个开销是无法避免的)
- 同时每次调用 select 都需要在内核遍历传递进来的所有 fd,这个开销在 fd 很多时也很大
- select 支持的文件描述符数量太小.
👥总结
本篇博文对 【Linux网络】深入解析I/O多路转接 - Select 做了一个较为详细的介绍,不知道对你有没有帮助呢
觉得博主写得还不错的三连支持下吧!会继续努力的~
相关文章:
【Linux网络】深入解析I/O多路转接 - Select
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
如何解决 Xcode 签名证书和 Provisioning Profile 过期问题
在 iOS 应用开发过程中,签名证书和 Provisioning Profile 是确保应用安全性和合法性的关键组件。然而,当这些证书或配置文件过期时,开发者可能会遇到编译或归档失败的问题。本文将详细介绍如何解决 Xcode 中“iOS Distribution”证书未找到和…...
[C++]C++20协程的原理
文章目录 协程的状态机Promise 对象挂起和恢复机制协程的执行流程示例代码分析 C 协程是 C20 引入的一项重要特性,它提供了一种更简洁、高效的异步编程方式。下面从协程的状态机、Promise 对象、挂起和恢复机制等方面介绍其底层实现原理。 协程的状态机 从底层角度…...
Oracle OCP证书有效期是三年?
这一段时间,网上经常传出消息Oracle OCM认证证书有效期为三年,其实这个假消息,通过博睿谷与Oracle官方人员确认,OCP认证证书有效期是永久的。 OCP证书本身永久有效,但老版本的OCP证书代表着更多的项目经验,…...
2025.4.29_STM32_看门狗WDG
1.WDG简介 大概意思就是给看门狗设置一个时间范围,在这个范围内必须喂狗(重置定时器),这个操作必须一直执行,比如看门狗的的时间范围是1-2秒,我们就必须间隔1-2秒就喂一次狗,否则它自减到0时就会重置电路,相…...
基于Java,SpringBoot,HTML水文水质监测预警系统设计
摘要 随着水资源管理需求的日益增长,构建高效、精准的水文监测预警系统至关重要。本文设计并实现了一套基于 Java、SpringBoot 和 HTML 技术的水文监测预警系统。系统采用 Java 语言与 SpringBoot 框架搭建后端服务,利用其强大的业务逻辑处理能力与高效…...
Qt开发:JSON字符串的序列化和反序列化
文章目录 一、构建和解析单个JSON对象二、JSON对象中嵌套多个JSON对象三、JSON对象中组建多个数组对象四、构建和解析数组对象 一、构建和解析单个JSON对象 1.1 JSON对象的构建 使用key-value形式生成JSON对象 #include <QJsonObject> #include <QJsonDocument> …...
第10次:电商项目配置开发环境
本次内容主要为给整个电商项目配置好开发环境,包括如下环节: 创建电商项目xiaoyu_mall,Django版本默认是最新的大版本5.2配置应用目录,因项目会涉及到多个应用,为保证项目结构清晰,将在项目下建立apps目录…...
【强化学习系列】Q-learning——从贝尔曼最优方程谈起
引言 上一篇贝尔曼最优方程中我们已经推导出动作价值形式的贝尔曼最优方程: q π ∗ ( s , a ) ∑ s ′ ∈ S ∑ r ∈ R p ( s ′ , r ∣ s , a ) [ r γ max a ′ q π ∗ ( s ′ , a ′ ) ] \begin{equation}q_{\pi^*}(s,a)\sum_{s\in S}\sum_{r\in R}p(s,…...
Java 基础--运算符全解析
【Java 基础】Java 运算符全解析:程序世界的“加减乘除”与“是非对错” 作者:IvanCodes 发布时间:2025年4月29日🐣 专栏:Java教程 嗨,各位 Java 探险家们!👋 掌握了变量、数据类…...
【神经网络与深度学习】改变随机种子可以提升模型性能?
引言 随机种子在机器学习和数据处理领域中至关重要,它决定了模型训练、数据划分以及参数初始化的随机性。虽然固定随机种子能确保实验的可重复性,但改变随机种子有时会意外提升模型性能。本文将探讨这一现象的潜在原因,并揭示随机性如何影响…...
一页概览:统一数据保护方案
2010年左右手绘,用的是公司的信纸,签字笔,马克笔。方案为统一数据保护。其实解释备份软件加备份硬件(支持重复数据删除)的联合解决方案。...
Python中的itertools模块常见函数用法示例
itertools ,迭代工具模块,提供了用于高效处理迭代器和组合问题的工具。 1. itertools.permutations(iterable, rNone) 功能:生成输入迭代器的所有可能排列。 参数: iterable:输入的可迭代对象。r:可选参数…...
微服务学习笔记
1 微服务 微服务:基于业务领域建模的、可独立发布的服务,把业务内聚的功能封装起来,并通过网络供其他服务访问。 好处: 技术异构性,不同服务可以使用不同的技术弹性,可以更好的处理服务不可用的问题扩展…...
实验七:基于89C51和DS18B20的温度采集与显示
一、实验目的 学习使用DS18B20数字温度传感器采集温度数据。使用4位共阳极数码管显示温度数据,显示精度到小数点后两位。熟悉89C51单片机的I/O口操作和位选控制。二、实验器材 89C51单片机开发板DS18B20数字温度传感器4位共阳极数码管三极管8550(用于位选驱动)电阻、电容等辅…...
cmake:基础
本文主要探讨cmake语法相关知识。 cmake(GUI)安装 apt install cmake-curses-gui cmake -y cmake语法 cmake_minimum_required(VERSION 版本号) 设置cmake最低版本 project(工程名) <> PROGECT_NAME/CMAKE_PROJECT_NAME 设置工程名字 add_library(库名 SHARED/STAT…...
1.8 点云数据获取方式——小结
点云,作为三维空间信息的直观载体,在各行各业都得到了广泛应用。而能够获得三维点云数据手段,也是极为丰富。本章节主要介绍了主动式手段(包括激光雷达、ToF相机、结构光相机)和被动式手段(双目立体相机、单…...
超越单体:进入微服务世界与Spring Cloud概述
大家好!欢迎来到我的新系列文章——《微服务架构:Spring Cloud实战指南》。在之前的《Java服务端核心技术》系列中,我们一起深入学习了如何使用Spring Boot构建功能强大、安全可靠的单体应用程序。我们掌握了Spring的核心原理、Web开发、数据…...
深度学习篇---模型权重变化与维度分析
文章目录 前言1. 权重的作用2. 权重的维度全连接层卷积层3. 权重的变化4.实例代码(PyTorch 框架)场景代码解释模型定义数据生成优化设置初始权重设置训练循环前向传播反向传播更新权重结果输出维度与变化总结维度匹配梯度跟新5. 增加网络深度:多层感知机(MLP)代码解释6. 权…...
AtCoder Beginner Contest 403(题解ABCDEF)
A - Odd Position Sum #1.奇数数位和 #include<iostream> #include<vector> #include<stdio.h> #include<map> #include<string> #include<algorithm> #include<queue> #include<cstring> #include<stack> #include&l…...
计算机视觉与深度学习 | 双目立体匹配算法理论+Opencv实践+matlab实践
双目立体匹配 一、双目立体匹配算法理论与OpenCV、matlab实践一、双目立体匹配理论二、OpenCV实践三、优化建议四、算法对比与适用场景二、双目立体匹配算法理论及Matlab实践指南一、双目立体匹配理论二、Matlab实践步骤三、算法对比与优化建议四、完整流程示例五、常见问题与解…...
深挖Java基础之:认识Java(创立空间/先导:Java认识)
今天我要介绍的是在Java中对Java的一些基本语法的认识与他们的运用,以及拟举例子说明和运用场景,优势和劣势, 注:本篇文章是对Java的一些基本的,简单的代码块的一些内容,后续会讲解在Java中的变量类型&…...
springmvc从请求到响应的流程分析
一、创建springmvc项目 通过网盘分享的文件:hello-springmvc.zip 链接: https://pan.baidu.com/s/1VmUHurgph661ND9LWqKhaw 提取码: b36a 二、从请求到响应流程 我们先画一下流程图,如下图所示。 三、源码解析 3.1 HttpServlet接收请求 用户发送htt…...
RabbitMQ 启动报错 “crypto.app“ 的解决方法
RabbitMQ 启动报错 “crypto.app” 的解决方法 在使用 RabbitMQ 时,有时会遇到启动报错的问题,其中一种常见的报错是: {"init terminating in do_boot",{error,{crypto,{"no such file or directory","crypto.app…...
idm 禁止自动更新提示(修改注册表)
目前版本:v 6.42 Bulid 35 运行-regedit- 计算机\HKEY_CURRENT_USER\SOFTWARE\DownloadManager 计算机\HKEY_CURRENT_USER\SOFTWARE\DownloadManagerLstCheck -> 0 重启...
LeetCode - 02.02.返回倒数第 k 个节点
目录 题目 解法一 双指针算法 原理 详细过程 为什么它有效? 时间复杂度与空间复杂度 代码 解法二 递归算法 核心思想 执行流程详解 具体例子 代码 题目 面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode) 解法一 双指针算…...
<c++>使用detectMultiScale的时候出现opencv.dll冲突
最近在试着弄一下opencv,看网上很多人都是的用的python,但是python跑起来没有c快,生成的qt工程也大一些,想着试试c看能不能生成opencv。然后就用到这个函数,detectMultiScale。 出现一个问题,就是我的程序在…...
从实列中学习linux shell脚本2: shell 的变量 方法 命名和使用规则之类 比如拿:获取cpu 负载,以及负载超过2.0 以后就发生邮件为例子
以下是对 Linux Shell 中变量、方法(函数)、命名规则的详细说明,并结合 获取CPU负载并在负载超过2.0时发送邮件 的示例进行演示: 1. Shell 变量 命名规则 命名格式:变量名由字母、数字、下划线组成,不能以…...
Centos Ubuntu RedOS系统类型下查看系统信息
文章目录 一、项目背景二、页面三、说明四、代码1.SysInfo2.EmsSysConfig3.HostInformationController4.HostInfo 一、项目背景 公司项目想展示当前部署系统的:操作系统,软件版本、IP、主机名。 二、页面 三、说明 说明点1:查询系统类型及…...
【Hive入门】Hive高级特性:视图与物化视图
在大数据分析中,Hive作为Hadoop生态系统中的重要组件,提供了强大的数据查询和管理能力。除了基本表的操作,Hive还支持 视图和 物化视图,这两种特性在数据管理和查询优化中扮演着重要角色。本文将深入探讨视图的创建与性能影响&…...
特征工程四-2:使用GridSearchCV 进行超参数网格搜索(Hyperparameter Tuning)的用途
1. GridSearchCV 的作用 GridSearchCV(网格搜索交叉验证)用于: 自动搜索 给定参数范围内的最佳超参数组合。交叉验证评估 每个参数组合的性能,避免过拟合。返回最佳模型,可直接用于预测或分析。 2. 代码逐行解析 (1…...
【Hive入门】Hive函数:内置函数与UDF开发
Apache Hive作为Hadoop生态系统中的重要组件,为大数据分析提供了强大的SQL-like查询能力。Hive不仅支持丰富的内置函数,还允许用户开发自定义函数(UDF)以满足特定需求。本文将深入探讨Hive的内置函数(包括数学函数、字…...
HTML Picture标签详细教程
HTML Picture标签详细教程 简介 <picture>标签是HTML5中引入的一个强大元素,它为开发者提供了更灵活的图像资源管理方式。该标签主要用于让浏览器根据不同条件(如设备屏幕大小、分辨率或支持的图像格式)选择最适合当前显示环境的图像…...
Html1
一,HTML概述 网页开发需要学习的知识: html css javaScript 两个框架 VUE.js ElementUI UI user interface 用户界面 HTML xml 可扩展标记语言-->存储数据 Markup Language标签语言都会提供各种标…...
runpod team 怎么设置自己的ssh key呢?
生成 ed25519 公钥密钥 ssh-keygen -t ed25519 -C "yourqq.com"然后在pod容器配置key以及启动方式 选择edit pod 添加启动代码 启动代码可以参考官方给的内容: https://docs.runpod.io/pods/configuration/use-ssh bash -c apt update;DEBIAN_FRONT…...
Flutter:组件10、倒计时
import dart:async; import package:flutter/material.dart;class CountdownTimer extends StatefulWidget {final int seconds;final double? fontSize;final Color? textColor;final bool showDays;final bool showHours;final bool showMinutes;final bool showSeconds;fi…...
存储器分类
按宏观分类 内部存储:用于临时存储当前程序运行所需要的数据外部存储:指硬盘,用于存储需要保存下的数据 按存储功能分 磁盘存储器(Disk),如机械硬盘非易失性存储器(Flash memory),分为固态硬…...
案例解析:基于量子计算的分子对接-QDOCK(Quantum Docking)
分子对接(Moleculardocking)在药物发现中具有重要意义,但对接的计算速度和准确率始终难以平衡,其巨大解搜索空间对传统计算机来说异常艰巨。 本文通过引入网格点匹配(GPM, Grind point matching)和特征原子…...
人工智能和机器学习在包装仿真中的应用与价值
引言 随着包装成为消费品关键的差异化因素,对智能设计、可持续性和高性能的要求比以往任何时候都更高 。为了满足这些复杂的期望,公司越来越多地采用先进的仿真方法,而现在人工智能 (AI) 和机器学习 (ML) 又极大地增强了这些方法 。本文探讨…...
系统的环境变量
目录 基本概念 用途之一 环境变量表 命令行参数表 理解 更多的环境变量 基本概念 环境变量(environmentvariables)⼀般是指在操作系统中⽤来指定操作系统运⾏环境的⼀些参数。环境变量通常具有某些特殊⽤途,还有在系统当中通常具有全局特性 用途之一 我们看…...
css3伸缩盒模型第一章(主轴以及伸缩盒模型)
css3伸缩盒模型第一章(主轴) 一、伸缩盒模型简介 2009 年, W3C 提出了一种新的盒子模型 —— Flexible Box (伸缩盒模型,又称:弹性盒 子)。它可以轻松的控制:元素分布方式、元素对齐方式、元素视觉顺序 ……...
【MySQL】(9) 视图
一、什么是视图 视图是一张虚拟表,是表、其它视图的查询结果集。它本身不像基础表(物理表)一样存储数据,而是将 SQL 查询语句包装起来,通过执行查询语句动态生成数据。 二、视图的作用 当我们需要频繁使用一条查询语句…...
day10 python机器学习全流程实践
在机器学习的实践中,数据预处理与模型构建是极为关键的环节。本文将回顾数据预处理的全流程,并基于处理后的数据完成简单的机器学习建模与评估,暂不涉及复杂的调参过程。 一、预处理流程回顾 机器学习的成功,很大程度上依赖于高…...
Rust Ubuntu下编译生成环境win程序踩坑指南
前言: 1,公司要给一线搞一个升级程序,需要在win下跑。 之前都是找开发总监帮忙,但是他最近比较忙。就让我自己搞。有了下文.。说来惭愧,之前写过一篇ubuntu下编译windows的文章。里面的demo就一句话 fuck world。依赖…...
2025年- H12-Lc119-56.合并区间(普通数组)---java版
1.题目描述 2.思路 思路参考了代码随想录: 按照左边界从小到大排序之后,如果 intervals[i][0] < intervals[i - 1][1] 即intervals[i]的左边界 < intervals[i - 1]的右边界,则一定有重叠。(本题相邻区间也算重贴ÿ…...
合并两个有序链表
题目:21. 合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 输入:l1 [1,2,4], l2 [1,3,4] 输出:[1,1,2,3,4,4]示例 2: 输入&#x…...
rsync命令详解与实用案例
rsync命令详解与实用案例 rsync是一款功能强大的Linux文件同步工具,通过高效的增量传输算法,能够显著减少数据传输量和时间,是备份、镜像和跨平台文件同步的理想选择。其核心价值在于只传输文件的差异部分,而非全量复制ÿ…...
gitee 如何修改提交代码的邮箱
gitee 如何修改提交代码的邮箱 1. 修改全局提交邮箱2. 修改特定仓库的提交邮箱3. 修改已提交记录的邮箱 4. 可能遇到的问题git filter-repo 拒绝执行解决办法方法一:使用 --force 参数 (亲测有效)方法二:创建一个全新的克隆仓库 注…...
MATLAB画一把伞
% 伞的参数num_ribs 5; % 伞骨数量修改为5R 1; % 伞的半径height 0.5; % 伞的高度handle_length 2; % 伞柄长度semicircle_radius 0.26; % 伞柄末端半圆的半径% 生成伞叶网格theta linspace(0, 2*pi, 100);phi linspace(0, pi/2, 50);[Theta, Phi] meshgrid(theta, phi…...
vue 实现文件流下载功能 前端实现文件流下载
首先场景就是,一般的文件下载是通过后端返回的文件地址下载文件,但当后端返回的是文件流的时候,下载要做特殊处理 案例截图: 下载成功: 代码处理,首先就是要在接口封装的地方加上 在 Vue 前端开发中实现文件流下载与普通文件下载的核心区别在于 数据处理方式。文件流…...