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

5.9-selcct_poll_epoll 和 reactor 的模拟实现

5.9-select_poll_epoll

本文演示 select 等 io 多路复用函数的应用方法,函数具体介绍可以参考我过去写的博客。

先绑定监听的文件描述符

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(struct sockaddr_in));serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(2052);if (-1 == bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr)))
{perror("bind");return -1;
}listen(sockfd, 10);

1. select

select 函数适用于 win/linux 平台,但是使用时每次都需要检查位图内所有客户端的状态变化情况,属于针对于每一个文件进行处理而非针对事件处理,效率较低。打个比方:如果客户端是小区内的住户,那么 selcet 作为快递员,会从快递仓库中挑选出要被配送到该小区指定住户的快递,并对于每一个住户是否有快递/寄快递。

演示如下:

fd_set rfds, rset;FD_ZERO(&rfds);
FD_SET(sockfd, &rfds);int maxfd = sockfd;
while (1)
{rset = rfds;int nready = select(maxfd + 1, &rset, NULL, NULL, NULL);if (FD_ISSET(sockfd, &rset)){struct sockaddr_in clientaddr;socklen_t len = sizeof(struct sockaddr_in);int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);printf("sockfd: %d\n", clientfd);FD_SET(clientfd, &rfds);maxfd = clientfd;}int i = 0;for (i = sockfd + 1; i <= maxfd; i++){if (FD_ISSET(i, &rset)){char buffer[128] = { 0 };int count = recv(i, buffer, 128, 0);if (0 == count){printf("disconnect\n");close(i);FD_CLR(i, &rfds);break;}send(i, buffer, count, 0);printf("clientfd: %d, count: %d, buffer: %s\n", i, count, buffer);}}
}

2. poll

poll 函数适用于 Linux 平台,效率相比于 select 有所提升。如果 selcet 是快递员要对于每一个住户确定一次需求,poll 则是可以直接锁定不同客户的需求。

演示如下:


struct pollfd fds[1024] = { 0 };fds[sockfd].fd = sockfd;
fds[sockfd].events = POLLIN;int maxfd = sockfd;while (1)
{int nready = poll(fds, maxfd + 1, -1);if (fds[sockfd].revents & POLLIN){struct  sockaddr_in clientaddr;int len = sizeof(struct sockaddr_in);int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);printf("hello, %d\n", clientfd);fds[clientfd].fd = clientfd;fds[clientfd].events = POLLIN;maxfd = clientfd;}int i = 0;for (i = sockfd + 1; i <= maxfd; i++){if (fds[i].revents & POLLIN){char buffer[128] = { 0 };int count = recv(fds[i].fd, buffer, 128, 0);if (count == 0){printf("disconnect\n");close(i);fds[i].fd = -1;fds[i].events = 0;continue;}send(i, buffer, count, 0);printf("clientfd: %d, sount: %d, lbuffer: %s\n", i, count, buffer);}}
}

3.1 epoll

在支持 Linux 的函数中,epoll 是最高效的。还是上面的比方,epoll 则是在一定程度上结合了前两者的优点,并且底层使用红黑树,查找速度更快。

演示如下:

int epfd = epoll_create(1);struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = sockfd;epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);struct epoll_event events[1024] = { 0 };while (1)
{int nready = epoll_wait(epfd, events, 1024, -1);int i = 0;for (i = 0; i < nready; i++){int curfd = events[i].data.fd;if (sockfd == curfd){struct sockaddr_in clientaddr;socklen_t len = sizeof(struct sockaddr_in);int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);ev.events = EPOLLIN;ev.data.fd = clientfd;epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);printf("clientfd: %d\n", clientfd);}else if (events[i].events & EPOLLIN){char buffer[10] = { 0 }; // 只要有数据就会一直触发,因此会回复多次int count = recv(curfd, buffer, 10, 0);if (count == 0){printf("disconnect\n");close(curfd);epoll_ctl(epfd, EPOLL_CTL_DEL, curfd, NULL);continue;}send(curfd, buffer, count, 0);printf("clientfd: %d, sount: %d, buffer: %s\n", curfd, count, buffer);}}}

3.2 基于 epoll 模拟实现面对事件的 reactor 的底层原理

定义结构体,为了方便,直接把 epfd 定位全局变量

#define BUFFER_LENGTH	1024typedef int (* RCALLBACK)(int fd);// save buffer data
struct conn_item
{int fd;char rbuffer[BUFFER_LENGTH];int rlen;char wbuffer[BUFFER_LENGTH];int wlen;union // 联合,在后续代码中会用到{RCALLBACK accept_callback;RCALLBACK recv_callback;}recv_t;RCALLBACK send_callback;
};struct conn_item connlist[1024];#if 1
int epfd;
#elif
struct reactor
{int epfd;struct conn_item connlist[1024];
};
#endif

reactor 的模拟借助以下回调函数实现,可以简化代码。

int set_cb(int fd, int event, int flag);
int accept_cb(int fd);
int recv_cb(int fd);
int send_cb(int fd);

具体实现如下,体现出面对事件的处理思想。

/*
1. listenfd 触发 EPOLLIN 事件 -> 执行 accept_cb
2. client 触发 EPOLLIN 事件 -> recv_cb
3. client 触发 EPOLLOUT 事件 -> send_cb
*/// ADD: flag == 1 else 0
int set_cb(int fd, int event, int flag)
{if (flag){struct epoll_event ev;ev.events = event;ev.data.fd = fd;epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);}else{struct epoll_event ev;ev.events = event;ev.data.fd = fd;epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);}
}int accept_cb(int fd)
{struct sockaddr_in clientaddr;socklen_t len = sizeof(struct sockaddr_in);int clientfd = accept(fd, (struct sockaddr*)&clientaddr, &len);set_cb(clientfd, EPOLLIN, 1);// set connlistconnlist[clientfd].fd = clientfd;memset(connlist[clientfd].wbuffer, 0, BUFFER_LENGTH);connlist[clientfd].wlen = 0;memset(connlist[clientfd].rbuffer, 0, BUFFER_LENGTH);connlist[clientfd].rlen = 0;// set callbackconnlist[clientfd].recv_t.recv_callback = recv_cb;connlist[clientfd].send_callback = send_cb;printf("clientfd: %d\n", clientfd);return clientfd;
}int recv_cb(int fd)
{char * buffer = connlist[fd].rbuffer;int index = connlist[fd].rlen;int count = recv(fd, buffer + index, BUFFER_LENGTH - index, 0);if (count == 0){printf("disconnect\n");epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);close(fd);return -1;}connlist[fd].rlen += count;#if ENABLE_HTTP_RESPONSE// 此处可以自行修改,使对应不同输入实现特定输出,如 http 相应:
http_response(&connlist[fd]);#else// 不做处理直接发送返回
memcpy(connlist[fd].wbuffer, connlist[fd].rbuffer, connlist[fd].rlen);
connlist[fd].wlen = connlist[fd].rlen;#endif// eventset_cb(fd, EPOLLOUT, 0);return count;
}int send_cb(int fd)
{char * buffer = connlist[fd].wbuffer;int index = connlist[fd].wlen;int count = send(fd, buffer, index, 0);// 事件来一次执行一次set_cb(fd, EPOLLIN, 0);return count;
}

mainloop 部分

int main()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(struct sockaddr_in));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);serveraddr.sin_port = htons(2048);if (-1 == bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))){perror("bind");return -1;}listen(sockfd, 10);connlist[sockfd].fd = sockfd;connlist[sockfd].recv_t.accept_callback = accept_cb;// epoll 边缘触发/*对于 IO 处理:随着时间增多会越来越复杂if(listenfd){...}else // clientfd{...}对于事件处理 -> reactor 对事件反应更缓和if (events & EPOLLIN){...}else if (events & EPOLLOUT){...}*/epfd = epoll_create(1); // int sizeset_cb(sockfd, EPOLLIN, 1);struct epoll_event events[1024] = { 0 };while (1) // main loop{int nready = epoll_wait(epfd, events, 1024, -1);int i = 0;for (i = 0; i < nready; i++){int curfd = events[i].data.fd;// 由于结构体内 accept_callback() 与 recv_callback() 共享同一块内存,故此处 if 条件判断可以省略。// if (sockfd == curfd)// {// 	// accept_cb()// 	// int clientfd = accept_cb(sockfd);// 	int clientfd = connlist[sockfd].recv_t.accept_callback(sockfd);// 	printf("client: %d\n", clientfd);// }if (events[i].events & EPOLLIN){// int count = recv_cb(curfd);int count = connlist[curfd].recv_t.recv_callback(curfd);if (count != -1)printf("recv <- clientfd: %d, count: %d, buffer: %s\n", curfd, count, connlist[curfd].rbuffer);}else if (events[i].events & EPOLLOUT){// int count = send_cb(curfd);int count = connlist[curfd].send_callback(curfd);printf("send -> clientfd: %d, count: %d, buffer: %s\n", curfd, count, connlist[curfd].wbuffer);}}}return 0;
}

附:本文的 http_response() 函数定义,以供测试使用。

#include <time.h>typedef struct conn_item connection_t;int http_response(connection_t *conn)
{const char *html_body = "<html><head><title>chipen.com</title></head><body><h1>chipen</h1></body></html>";int content_length = strlen(html_body);// 生成符合 HTTP 标准格式的 Date 字符串time_t now = time(NULL);struct tm *gmt = gmtime(&now);char date_str[128];strftime(date_str, sizeof(date_str), "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", gmt);// 构建完整的 HTTP 响应conn->wlen = snprintf(conn->wbuffer, BUFFER_LENGTH,"HTTP/1.1 200 OK\r\n""Content-Type: text/html\r\n""Content-Length: %d\r\n""Accept-Ranges: bytes\r\n""%s""\r\n"  // Header 与 Body 的分隔符"%s",   // HTML 内容content_length,date_str,html_body);return conn->wlen;
}

相关文章:

5.9-selcct_poll_epoll 和 reactor 的模拟实现

5.9-select_poll_epoll 本文演示 select 等 io 多路复用函数的应用方法&#xff0c;函数具体介绍可以参考我过去写的博客。 先绑定监听的文件描述符 int sockfd socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(struc…...

图上思维:基于知识图的大型语言模型的深层可靠推理

摘要 尽管大型语言模型&#xff08;LLM&#xff09;在各种任务中取得了巨大的成功&#xff0c;但它们经常与幻觉问题作斗争&#xff0c;特别是在需要深入和负责任的推理的场景中。这些问题可以通过在LLM推理中引入外部知识图&#xff08;KG&#xff09;来部分解决。在本文中&am…...

37-智慧医疗服务平台(在线接诊/问诊)

系统功能特点&#xff1a; 技术栈: springBootVueMysql 功能点: 医生端 用户端 管理员端 医生端: 科室信息管理、在线挂号管理、预约体检管理、体检报告管理、药品信息管理、处方信息管理、缴费信息管理、病历信息管理、智能导诊管理、在线接诊患者功能 (和患者1V1沟通) 用户…...

【新品发布】VXI可重构信号处理系统模块系列

VXI可重构信号处理系统模块概述 VXI可重构信号处理系统模块包括了 GPU 模块&#xff0c;CPU 模块&#xff0c;射频模块、IO 模块、DSP模块、高速存储模块、交换模块&#xff0c;采集处理模块、回放处理模块等&#xff0c;全套组件为单体3U VPX架构&#xff0c;可自由组合到多槽…...

React 第三十八节 Router 中useRoutes 的使用详解及注意事项

前言 useRoutes 是 React Router v6 引入的一个钩子函数&#xff0c;允许通过 JavaScript 对象&#xff08;而非传统的 JSX 语法&#xff09;定义路由配置。这种方式更适合复杂路由结构&#xff0c;且代码更简洁易维护。 一、基础使用 1.1、useRoutes路由配置对象 useRoute…...

Redhat 系统详解

Red Hat 系统深度解析&#xff1a;从企业级架构到核心组件 一、Red Hat 概述&#xff1a;企业级 Linux 的标杆 Red Hat 是全球领先的开源解决方案供应商&#xff0c;其核心产品 Red Hat Enterprise Linux&#xff08;RHEL&#xff09; 是企业级 Linux 的黄金标准。RHEL 以 稳…...

docker常用命令总结

常用命令含义docker info查看docker 服务的信息-------------------------镜像篇docker pull XXX从官网上拉取名为XXX的镜像docker login -u name登录自己的dockerhub账号docker push XXX将XXX镜像上传到自己的dockerhub账户中&#xff08;XXX的命名必须是用户名/镜像名&#x…...

【el-admin】el-admin关联数据字典

数据字典使用 一、新增数据字典1、新增【图书状态】和【图书类型】数据字典2、编辑字典值 二、代码生成配置1、表单设置2、关联字典3、验证关联数据字典 三、查询操作1、模糊查询2、按类别查询&#xff08;下拉框&#xff09; 四、数据校验 一、新增数据字典 1、新增【图书状态…...

component :is是什么?

问&#xff1a; component &#xff1a;is是什么&#xff1f; 是组件&#xff1f; 那我们是不是就不需要自己创建组件了&#xff1f;还是什么意思&#xff1f;component &#xff1a;is和什么功能是类似的&#xff0c;同时和类似功能相比对什么时候用component &#xff1a;is…...

适老化洗浴辅具产业:在技术迭代与需求升级中重塑银发经济新生态

随着中国人口老龄化程度的不断加深&#xff0c;老年群体对于适老化产品的需求日益增长。 适老化洗浴辅具作为保障老年人洗浴安全与舒适的关键产品&#xff0c;其发展状况备受关注。 深入剖析中国适老化洗浴辅具的发展现状&#xff0c;并探寻助力产业发展的有效路径&#xff0…...

『Python学习笔记』ubuntu解决matplotlit中文乱码的问题!

ubuntu解决matplotlit中文乱码的问题&#xff01; 文章目录 simhei.ttf字体下载链接&#xff1a;http://xiazaiziti.com/210356.html将字体放到合适的地方 sudo cp SimHei.ttf /usr/share/fonts/(base) zkfzkf:~$ fc-list | grep -i "SimHei" /usr/local/share/font…...

从AI到新能源:猎板PCB的HDI技术如何定义高端制造新标准?

2025年&#xff0c;随着AI服务器、新能源汽车、折叠屏设备等新兴领域的爆发式增长&#xff0c;高密度互连&#xff08;HDI&#xff09;电路板成为电子制造业的“必争之地”。HDI板凭借微孔、细线宽和高层间对位精度&#xff0c;能够实现电子设备的高集成化与微型化&#xff0c;…...

汽车制造行业的数字化转型

嘿&#xff0c;大家好&#xff01;今天来和大家聊聊汽车制造行业的数字化转型&#xff0c;这可是当下非常热门的话题哦&#xff01; 随着科技的飞速发展&#xff0c;传统的汽车制造行业正经历着一场深刻的变革。数字化技术已经不再是“锦上添花”&#xff0c;而是车企能否在未…...

Redis 常见数据类型

Redis 常见数据类型 一、基本全局命令详解与实操 1. KEYS 命令 功能&#xff1a;按模式匹配返回所有符合条件的键&#xff08;生产环境慎用&#xff0c;可能导致阻塞&#xff09;。 语法&#xff1a; KEYS pattern 模式规则&#xff1a; h?llo&#xff1a;匹配 hello, ha…...

【计算机网络-传输层】传输层协议-TCP核心机制与可靠性保障

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;传输层协议-UDP 下篇文章&#xff1a; 网络层 我们的讲解顺序是&…...

对golang中CSP的理解

概念&#xff1a; CSP模型&#xff0c;即通信顺序进程模型&#xff0c;是由英国计算机科学家C.A.R. Hoare于1978年提出的。该模型强调进程之间通过通道&#xff08;channel&#xff09;进行通信&#xff0c;并通过消息传递来协调并发执行的进程。CSP模型的核心思想是“不要通过…...

嵌入式openharmony标准系统中HDF框架底层原理分析

1、案例简介 该程序是基于OpenHarmony标准系统编写的基础外设类:简易HDF驱动。 2、基础知识 2.1、OpenHarmony HDF开发简介 HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。旨在构建统一…...

238.除自身以外数组的乘积

给你一个数组&#xff0c;求出第 i 个元素以外的数组元素的乘积&#xff0c;不能使用除法&#xff0c;且时间复杂度O(n), 对于一个数&#xff0c;如果知道了前缀元素的乘积和后缀元素的乘积&#xff0c;就知道了这个元素以外的数组元素的乘积&#xff0c;所以现在的问题是如何…...

AI文旅|暴雨打造旅游新体验

今年"五一"假期&#xff0c;全国文旅市场迎来爆发式增长&#xff0c;从丈崖瀑布的磅礴水雾到城市商区的璀璨霓虹&#xff0c;从山野民宿的静谧悠然到主题乐园的欢腾喧嚣&#xff0c;处处人潮涌动。在这火热的景象背后&#xff0c;一股“无形之力”正悄然改变旅游体验…...

学习心得《How Global AI Policy and Regulations Will Impact Your Enterprise》Gartner

AI时代来临,然而与之对应的是海量的数据的安全性和合规性如何保障,如何平衡个人与智能体的利益,恰巧,最近Gartner发布了《How Global AI Policy and Regulations Will Impact Your Enterprise》,我们就其中的观点一起进行探讨。 战略规划假设 我们首先关注的是关键的战略…...

JAVA将一个同步方法改为异步执行

目的&#xff1a; 这么做的目的就是为了使一个高频率执行的方法能不阻塞整个程序&#xff0c;将该方法丢入到线程池中让线程去做异步执行&#xff0c;既提高了程序整体运行速度&#xff0c;也使得在高并发环境下程序能够更加健壮&#xff08;同步执行可能会使得请求堆积以致系…...

对遗传算法思想的理解与实例详解

目录 一、概述 二、实例详解 1&#xff09;问题描述与分析 2&#xff09;初始化种群 3&#xff09;计算种群适应度 4&#xff09;遗传操作 5&#xff09;基因交叉操作 6&#xff09;变异操作 三、计算结果 四、总结 一、概述 遗传算法在求解最优解的问题中最为常用&a…...

数据可视化大屏——物流大数据服务平台(二)

代码分析&#xff1a; 物流大数据平台代码分析 这是一个基于 Bootstrap 和 ECharts 构建的物流大数据平台前端页面&#xff0c;设计采用了经典的三栏布局&#xff0c;主要展示河南省及全国的物流数据可视化内容。下面从多个维度进行分析&#xff1a; 1. 页面结构分析 整体采…...

MindSpore框架学习项目-ResNet药物分类-构建模型

目录 2.构建模型 2.1定义模型类 2.1.1 基础块ResidualBlockBase ResidualBlockBase代码解析 2.1.2 瓶颈块ResidualBlock ResidualBlock代码解释 2.1.3 构建层 构建层代码说明 2.1.4 定义不同组合(block&#xff0c;layer_nums)的ResNet网络实现 ResNet组建类代码解析…...

ChatTempMail - AI驱动的免费临时邮箱服务

在当今数字世界中&#xff0c;保护在线隐私的需求日益增长。ChatTempMail应运而生&#xff0c;作为一款融合人工智能技术的新一代临时邮箱服务&#xff0c;它不仅提供传统临时邮箱的基本功能&#xff0c;还通过AI技术大幅提升了用户体验。 核心功能与特性 1. AI驱动的智能邮件…...

(leetcode) 力扣100 9.找到字符串中所有字母异位词(滑动窗口)

题目 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 数据范围 1 < s.length, p.length < 3 * 104 s 和 p 仅包含小写字母 样例 示例 1: 输入: s "cbaebabacd", p &quo…...

深入了解 Stable Diffusion:AI 图像生成的奥秘

一、引言 AI 艺术与图像生成技术的兴起改变了我们创造和体验视觉内容的方式。在过去几年里&#xff0c;深度学习模型已经能够创造出令人惊叹的艺术作品&#xff0c;这些作品不仅模仿了人类艺术家的风格&#xff0c;甚至还能创造出前所未有的新风格。在这个领域&#xff0c;Sta…...

场外期权平值期权 实值期权 虚值期权有什么区别?收益如何计算?

​​期权汇 场外期权按价值状态分为平值、虚值、实值期权。 01&#xff5c;实值期权对于看涨期权而言&#xff0c;如果行权价格低于标的市场价格&#xff0c;则该期权处于实值状态&#xff1b;对于看跌期权&#xff0c;如果行权价格高于标的市场价格&#xff0c;则处于实值状态…...

微软系统 红帽系统 网络故障排查:ping、traceroute、netstat

在微软&#xff08;Windows&#xff09;和红帽&#xff08;Red Hat Enterprise Linux&#xff0c;RHEL&#xff09;等系统中&#xff0c;网络故障排查是确保系统正常运行的重要环节。 ping、traceroute&#xff08;在Windows中为tracert&#xff09;和netstat是三个常用的网络…...

HOT 100 | 【子串】76.最小覆盖子串、【普通数组】53.最大子数组和、【普通数组】56.合并区间

一、【子串】76.最小覆盖子串 1. 解题思路 定义两个哈希表分别用于 t 统计字符串 t 的字符个数&#xff0c;另一个sub_s用于统计字符串 t 在 s 的子串里面字符出现的频率。 为了降低时间复杂度&#xff0c;定义一个变量t_count用于统计 t 哈希表中元素的个数。哈希表sub_s是一…...

基于CNN的猫狗图像分类系统

一、系统概述 本系统是基于PyTorch框架构建的智能图像分类系统&#xff0c;专门针对CIFAR-10数据集中的猫&#xff08;类别3&#xff09;和狗&#xff08;类别5&#xff09;进行分类任务。系统采用卷积神经网络&#xff08;CNN&#xff09;作为核心算法&#xff0c;结合图形用…...

《时序数据库全球格局:国产与国外主流方案的对比分析》

引言 时序数据库&#xff08;Time Series Database, TSDB&#xff09;是专门用于存储、查询和分析时间序列数据的数据库系统&#xff0c;广泛应用于物联网&#xff08;IoT&#xff09;、金融、工业监控、智能运维等领域。近年来&#xff0c;随着大数据和物联网技术的发展&…...

力扣-2.两数相加

题目描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都…...

富乐德传感技术盘古信息 | 锚定“未来工厂”新坐标,开启传感器制造行业数字化转型新征程

在数字化浪潮下&#xff0c;制造业正经历深刻变革。 传感器作为智能制造的核心基础部件&#xff0c;正面临着质量精度要求升级、交付周期缩短、成本管控严苛等多重挑战。传统依赖人工纸质管理、设备数据孤岛化的生产模式&#xff0c;已成为制约高端传感器制造突破“高精度、高…...

RT-Thread 深入系列 Part 2:RT-Thread 内核核心机制深度剖析

摘要&#xff1a; 本文从线程管理、调度器原理、中断处理与上下文切换、IPC 同步机制、内存管理五大核心模块出发&#xff0c;深入剖析 RT-Thread 内核实现细节&#xff0c;并辅以源码解读、流程图、时序图与性能数据。 目录 线程管理与调度器原理 1.1 线程控制块&#xff08;T…...

uni-app,小程序自定义导航栏实现与最佳实践

文章目录 前言为什么需要自定义导航栏&#xff1f;基本实现方案1. 关闭原生导航栏2. 自定义导航栏组件结构3. 获取状态栏高度4. 样式设置 内容区域适配跨平台适配要点iOS与Android差异处理 常见导航栏效果实现1. 透明导航栏2. 滚动渐变导航栏3. 自定义返回逻辑 解决常见问题1. …...

小程序消息订阅的整个实现流程

以下是微信小程序消息订阅的完整实现流程&#xff0c;分为 5个核心步骤 和 3个关键注意事项&#xff1a; 一、消息订阅完整流程 步骤1&#xff1a;配置订阅消息模板 登录微信公众平台进入「功能」→「订阅消息」选择公共模板或申请自定义模板&#xff0c;获取模板ID&#xff…...

istio in action之Gateway流量入口与安全

入口网关&#xff0c;简单来说&#xff0c;就是如何让外部世界和我们精心构建的集群内部服务顺畅地对话。在网络安全领域&#xff0c;有一个词叫流量入口&#xff0c;英文叫Ingress。这指的是那些从我们自己网络之外&#xff0c;比如互联网&#xff0c;发往我们内部网络的流量。…...

LeetCode 1722. 执行交换操作后的最小汉明距离 题解

示例&#xff1a; 输入&#xff1a;source [1,2,3,4], target [2,1,4,5], allowedSwaps [[0,1],[2,3]] 输出&#xff1a;1 解释&#xff1a;source 可以按下述方式转换&#xff1a; - 交换下标 0 和 1 指向的元素&#xff1a;source [2,1,3,4] - 交换下标 2 和 3 指向的元…...

区块链详解

1. 引言 1.1 背景 在数字化时代&#xff0c;信息的存储、传输和验证面临诸多挑战&#xff0c;如数据篡改、信任缺失、中心化风险等。区块链技术应运而生&#xff0c;作为一种分布式账本技术&#xff0c;它通过去中心化、去信任化、不可篡改等特性&#xff0c;为解决这些问题提…...

申能集团笔试1

目录 注意 过程 注意 必须开启摄像头和麦克风 只能用网页编程&#xff0c;不能用本地环境 可以用Index进行测试 过程 我还以为是编程&#xff0c;没想到第一次是企业人际关系、自我评价的选择题&#xff0c;哈哈哈有点轻松&#xff0c;哦对他要求不能泄漏题目&#xff0c…...

机器人手臂的坐标变换:一步步计算齐次矩阵过程 [特殊字符]

大家好!今天我们来学习如何计算机器人手臂的坐标变换。别担心,我会用最简单的方式解释这个过程,就像搭积木一样简单! 一、理解问题 我们有一个机器人手臂,由多个关节组成。每个关节都有自己的坐标系,我们需要计算从世界坐标系(W)到末端执行器(P₃)的完整变换。 二、已…...

神经元和神经网络定义

在深度学习中&#xff0c;神经元和神经网络是构成神经网络模型的基本元素。让我们从基础开始&#xff0c;逐步解释它们的含义和作用。 1️⃣ 神经元是什么&#xff1f; 神经元是神经网络中的基本计算单元&#xff0c;灵感来自于生物神经系统中的神经元。每个人的脑中有数以亿…...

Vue——Axios

一、Axios 是什么 Axios 是一个基于 promise 网络请求库&#xff0c;作用于 node.js 和浏览器中。 它是 isomorphic 的 ( 即同一套代 码可以运行在浏览器和 node.js 中 ) 。在服务端它使用原生 node.js http 模块 , 而在客户端 ( 浏览端 ) 则使 用 XMLHttpRequest…...

力扣:轮转数组

题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 例子 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5…...

TCP/IP协议的体系结构

文章目录 前言数据链路层网络层传输层应用层 前言 TCP/IP通信体系主要分为四个层次&#xff0c;从底至上分别为&#xff1a; 数据链路层 >网络层 > 传输层 >应用层 该体系的工作原理主要依靠封装与分用的使用完成对信息的传递与解析。 1. 所谓封装&#xff0c;就是上层…...

Vue3 中 ref 与 reactive 的区别及底层原理详解

一、核心区别 1. 数据类型与使用场景 • ref 可定义基本类型&#xff08;字符串、数字、布尔值&#xff09;和对象类型的响应式数据。对于对象类型&#xff0c;ref 内部会自动调用 reactive 将其转换为响应式对象。 语法特点&#xff1a;需通过 .value 访问或修改数据&#…...

MySQL 与 Elasticsearch 数据一致性方案

MySQL 与 Elasticsearch 数据一致性方案 前言一、同步双写&#xff08;Synchronous Dual Write&#xff09;&#x1f504;二、异步双写&#xff08;Asynchronous Dual Write&#xff09;&#x1f4e4;三、定时同步&#xff08;Scheduled Synchronization&#xff09;&#x1f5…...

rust-candle学习笔记11-实现一个简单的自注意力

参考&#xff1a;about-pytorch 定义ScaledDotProductAttention结构体&#xff1a; use candle_core::{Result, Device, Tensor}; use candle_nn::{Linear, Module, linear_no_bias, VarMap, VarBuilder, ops};struct ScaledDotProductAttention {wq: Linear,wk: Linear,wv: …...

RabbitMQ-运维

文章目录 前言运维-集群介绍多机多节点单机多节点 多机多节点下载配置hosts⽂件配置Erlang Cookie启动节点构建集群查看集群状态 单机多节点安装启动两个节点再启动两个节点验证RabbitMQ启动成功搭建集群把rabbit2, rabbit3添加到集群 宕机演示仲裁队列介绍raft算法协议 raft基…...