网络基础知识梳理和Muduo库使用
文章目录
- 网络基础知识梳理和Muduo库使用
- 1.知识储备
- 2.阻塞、非阻塞、同步、异步
- 我的总结
- 3.Unix/Linux上的五种IO模型
- 0.铺垫
- 1.阻塞IO(blocking)
- 2.非阻塞IO(non-blocking)
- 3.IO复用(IO multiplexing)
- 4.信号驱动(Signal-driven)[Linux特有]
- 5.异步IO(asynchronous)
- 4.好的网络服务器设计
- epoll+fork 不如 epoll+pthread ?
- 5.Reactor模型
- 6.IO复用接口总结
- 1.select和poll的缺点
- 2.epoll原理以及优势
- 1.LT模式(水平触发,默认模式)
- 2.ET模式(边缘触发)
- 3.muduo采用的是LT
- 7.moduo网络库编程
- 1.muduo源码编译安装
- 2.muduo网络库服务器编程
网络基础知识梳理和Muduo库使用
1.知识储备
- TPC协议和UDP协议
- TCP编程和UDP编程步骤
- IO复用接口编程select、poll、epoll编程
- Linux的多线程编程pthread、进程和线程模型,Cpp20标准加入了协程的支持,更轻量级的线程,完全支持用户态的支持,在golang里面已经内置到语言级了。
2.阻塞、非阻塞、同步、异步
一个典型网络IO的两个阶段:数据准备 和 数据读写
网络IO阶段一:数据准备/就绪(TCP接收缓冲区)
- 阻塞:调用IO方法的线程进入阻塞状态
- 非阻塞:不会改变线程的状态,通过返回值判断
常见的IO接口:size_t recv(int sockfd,void* buf,size_t len,int flags);
int size=recv(sockfd,buf,1024,0);
//这个sockfd就是系统文件描述符,就是一个IO,默认是阻塞的,如果scokfd上没有数据可读,recv不会返回,一直阻塞,直到等到这个sockfd上有数据可读//非阻塞,while循环,cpu空转,直到数据准备好/*
size==-1 && errno==EAGAIN 正常的非阻塞返回,sockfd上无网络事件
size==0 网络对端关闭了连接close(fd)
size>0 recv从sockfd上接收到网络事件,读到数据
*/
网络IO阶段二:数据读写
- IO的同步:【用户自己调用】recv将TCP接收缓冲区中的数据搬到用户层定义的buf中,花的都是自己的时间!
- IO的异步:当用户请求内核的时候,用户关心sockfd上的数据,【用户】请求【OS】当TCP接收缓冲区数据就绪后,将数据拷入用户的buf缓冲区中,同时注册一个sigio信号【or 回调函数】,之后应用程序玩自己的了!当OS拷贝完成,通过sigio通知【异步程序最大的标识】,用户看到的是buf的数据已经准备好了!
- 在【处理IO,读/写/等待】的时候,阻塞和非阻塞都是同步IO,只有使用了【特殊的API,内核需要提供相关API,不提供就没有!】才是异步IO
/*
Linux提供的同步IO接口 recv,send
*/
char buf[1024]={0};
/*recv数据准备好了以后,OS会将该sockfd对于的TCP接收缓冲区不断的把数据往应用层的buf里面搬,通过recv的返回值给用户这里就叫做IO的同步,是用户自己去TCP缓冲区拿取数据
*/
int size=recv(sockfd,buf,1024,0);
if(size >0){buf//处理
}
/*
Linux提供的异步IO接口 aio_read,aio_write
*/
aio_read(aiocb,...);
aio_write(aiocb,...);struct aiocb{int aio_fildes; //sockfdoff_t aio_offset;volatile void* aio_buf;//用户空间的buf,输出型参数size_t aio_nbytes;int aio_reqprio;struct sigevent aio_sigevent;//通知方式,信号int aio_lio_opcode;
};
Node.js:基于异步非阻塞模式下的高性能服务器!任何操作都是传入一个数据和一个回调!典型的异步方式的编程。
业务层面的一个逻辑处理,是同步 还是 异步 ???
- 同步:A操作等待B操作做完事情,得到返回值,继续处理。
- 异步:A操作告诉B操作它感兴趣的事件以及通知方式,A操作继续执行自己的业务逻辑,等B监听到相应的事件发生后,B会通知A,A开始相应的数据/操作处理逻辑。
我的总结
阻塞,非阻塞,同步,异步描述的都是IO的状态,一次网络IO通常分为两个阶段,分为数据就绪和数据读写!
比如系统提供的IO接口recv/read,传入sockfd,buf大小,数据是否就绪就是去看内核中的TCP接收缓冲区有无数据可读。
当工作在阻塞状态下的recv,当内核中的TCP接收缓冲区中没有数据可读就阻塞住,如果是非阻塞状态下的recv,则通过判断返回值观察数据是否就绪。一般设计成while循环,让cpu不停的空转,直到数据准备好。
当数据就绪,则进入IO的第二阶段:数据读写阶段,如果是应用层自己调用recv,花费自己的时间,将TCP接收缓冲区的数据拷贝进用户传给接口的buf中,用户等待recv拷贝完成后才返回,这就叫同步。
如果是异步IO,当用户去调用异步IO接口,不会像调用同步IO那么简单,异步IO接口通常需要用户传入sockfd,buf,【通知方式】,通知方式一般是信号或者回调,让OS负责监听TCP缓冲区上是否有数据可读,这个时候用户就可以去做自己的事情了!如果有数据可读,OS会将TCP缓冲区上的数据拷贝到用户传入的buf中,操作完成后OS通过信号或者回调函数通知用户操作已完成。
3.Unix/Linux上的五种IO模型
0.铺垫
一个典型的网络IO接口调用,分为两个阶段,分别为“数据就绪”和“数据读写”,数据就绪阶段分为阻塞和非阻塞,表现的结果就是,阻塞当前线程还是直接返回。
同步表示A向B请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),数据的读写都是由请求方A自己来完成的(不管是阻塞还是非阻塞);异步表示A向B请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),向B传入请求事件以及事件发生时通知的方式,A就可以处理其他逻辑了,当B监听到事件处理完成后,会用事先约定好的通知方式,通知A处理结果。
- 同步阻塞:int size = recv(fd,buf,1024,0); 数据准备好才返回【阻塞】,准备好后,用户再自己去TCP缓冲区拷贝数据到用户buf【同步】
- 同步非阻塞:int size = recv(fd,buf,1024,0); 立刻得到返回值【非阻塞】,需要判断返回值才能直到数据有没有准备好。准备好了之后还是用户自己去TCP缓冲区拷贝数据【同步】。
- 异步阻塞:理论上有,但不合理!A向B提出请求后【异步】,A还要【阻塞着等待B的通知,因为阻塞是数据准备好才返回】,完全是在浪费线程A处理事件的能力。也就是说,在这种工作模式下,A告诉B某任务后,A啥也不干就死等,直到数据准备好 && B将数据从TCP缓冲区中拷贝到用户buf中后,A才继续。
- 异步非阻塞:用户调用异步接口【异步】,传入参数后,就啥也不管了【非阻塞】。内核完成后所有任务后告诉用户。
1.阻塞IO(blocking)
用户调用read/recv,便开始了等待,一直的等待。默认的sockfd是阻塞的,并没有通过setsockopt接口将sockfd设置为非阻塞sockfd,则应用程序调用read时,数据未准备好就阻塞住。等待数据【IO阶段1】,数据从内核空间拷贝到用户空间【IO阶段2】,做完IO两阶段事务后,唤醒进程/线程。
这种模型效率不高,但是编程简单。
2.非阻塞IO(non-blocking)
调用read/recv之前,调用setsockopt接口将sockfd设置为非阻塞,于是进入非阻塞IO,在内核数据未准备好 -> 数据准备好拷贝数据这个过程,用户调用read/recv会马上拿到返回值,用户对拿到的返回值进行判断。当数据准备好后,数据从内核空间拷贝到用户空间,占用的还是用户的时间,所以非阻塞IO也是一种同步IO过程!
3.IO复用(IO multiplexing)
进程阻塞于select/poll/epoll,通过timeout参数设置超时时间也可以让进程/线程工作在非阻塞条件下。也是同步的过程!IO复用和非阻塞IO有什么区别呢?在非阻塞IO中,我们是通过循环检查等待数据就绪的,而在IO复用中,我们通过调用IO多路复用接口select/poll/epoll来完成这件事,多路复用接口会将可读的fd返回。一个线程通过调用IO复用接口可以监听很多很多的sockfd,不像前面的一个线程只能处理一个sockfd。注意I/O复用优化的是等待数据的时间。当多个sockfd可读/可写,IO复用接口会将这些可读/可写的sockfd组织成列表进行返回。
4.信号驱动(Signal-driven)[Linux特有]
数据未就绪 -> 数据就绪,应用线程完全放飞自我,可以去做自己的事情!而前面的IO方式因为没有提前协商通知方式,所以只能阻塞住或者不断的去查询是否准备好。而信号驱动用户向内核注册sigaction信号,内核立刻返回ok,告诉用户你可以放飞自我了,想去做什么就去做吧!在整个数据等待的过程中,应用进程毫不关心,在IO的一阶段是异步的!当数据就绪后,通过注册好的信号给用户通知。但是将数据从内核空间拷贝到用户空间,这里还是得用户自己去调用read/recv接口去获取,所以在第二阶段是同步的!所以信号驱动是异步非阻塞+同步。
5.异步IO(asynchronous)
异步的非阻塞IO是最典型的!整个流程完全不需要关心,用户调用相关的接口后,IO的一阶段和二阶段全部由内核去完成。拷贝完成后,内核通过事先注册的信号通知用户,用户此时对数据进行相关的处理即可!异步IO是效率最高的,但同时编程也最为复杂,出事概率大!
典型的异步非阻塞IO模型【Node.js】
4.好的网络服务器设计
在多核时代,服务器网络编程如何选择线程模型呢?赞同live作者的观点:one loop per thread is usually a good model,这样多线程服务端的编程问题就转换为如何设计一个高效且易于使用的event loop,然后每个线程run一个event loop就行了(当然线程间的同步、互斥少不了,还有其他的耗时事件需要另外的线程来做)
event loop 是 non-blocking 网络编程的核心,在现实生活中,non-blocking 几乎总是和 IO-multiplexing 一起使用,原因由两点:
- 没有人真的会用轮询(busy-pooling)来检查某个non-blocking IO 操作是否完成,这样太浪费CPU资源了!
- IO-multiplex一般不能和blocking IO用在一起,因为blocking IO中的read()/write()/accept()/connect() 都有可能会阻塞当前线程【因为sockfd是阻塞的!】,IO复用接口给用户返回的sockfd都是阻塞的!用户万一被阻塞在了这个sockfd上【用户需要调用read去读取该sockfd】,epoll_wait()就等不到线程去运行它了,那该线程就没有办法处理其他socket上的IO事件了。
所以,当我们提到non-blocking的时候,实际上指的是non-blocking + IO-multiplexing,通过IO复用操作非阻塞sockfd,单用其中任何一个都没有办法很好的实现功能。
epoll+fork 不如 epoll+pthread ?
强大的nginx服务器采用了epoll+fork模型作为网络模块的架构设计,实现了简单好用的负载算法,使各个fork网络进行不会忙的越忙、闲的越闲,并且通过引入一把乐观锁解决了该模型导致的服务器惊群线程,功能十分强大!
5.Reactor模型
The reactor design pattern is an event handling pattern for handling service requestsdelivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.
四个重要组件:Event事件、Reactor反应堆、Demultiplex事件分发器、Evanthandler事件处理器,下面是一个Single-Reactor模型:
Event 就是 fd+事件类型/读/写
- 把事件注册到反应堆上(将Event和对应的Handler给Reactor反应堆),即反应堆Reactor存储了事件和处理的集合,反应堆维护了Event和对应的Handler
- 反应堆本质就是一个epoll模型,通过Epoll add/mod/del Event向事件分发器中添加事件,启动事件分发器,多路复用开启。
- 事件分发器Demultiplex,开启事件循环epoll_wait【阻塞】,监听新用户的连接或者已连接用户的读写事件,如果epoll_wait监听到有新的事件产生,事件分发器返回发生事件的Event给Reactor,因为Reactor中注册过Event对应的Handler。
- Reactor调用Event对应的事件处理器EventHandler【一般通过map表存储】,处理事件【read->decode->compute->encode->send】
muduo库其实是一个Multiple Reactors模型,模型结构如下:
相当于:mainReactor和subReactor 把reactor和demultiplex合一了。,下面的【read-decode->compute->encode->send 】就是对应响应事件的处理!这张图意思就是我们开启多线程,每个线程上都运行一个Reactor模型!
6.IO复用接口总结
1.select和poll的缺点
select的缺点:
- 单个进程能够监听的文件描述符的数量存在最大限制,通常是1024,虽然可以更改,但由于select采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差!(Linux内核中:#define __FD_SETSIZE 1024)【select的最大缺陷】
- 内核/用户空间内存拷贝问题,select需要复制大量的文件描述符【fd】,产生巨大的开销
- select采用位数组,用户空间和内核空间都要不断的遍历位数组才能知道哪些事件【fd】响应。
- select触发的方式是水平触发【LT】,应用程序如果没有完成对一个已经就绪文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程。【select,poll,工作在LT模式下的epoll都有这个问题!】
相比select模型,poll是使用链表保存文件描述符,因此没有了监听文件数量的限制,但是其他三个缺点依然存在。
- 轮询开销:与 select 类似,返回后需遍历整个
pollfd
数组判断哪些 fd 就绪,时间复杂度 O (n)。 - 内核遍历检测:内核底层仍需遍历所有 fd 检查就绪状态,效率未根本提升。
- 用户态 / 内核态拷贝:每次调用需将 fd 数组从用户态拷贝到内核态,fd 较多时开销显著。
举例:以select模型为例,假设我们的服务器需要支持100万的并发连接,则在__FD_SETSIZE 为1024的情况下,则我们至少需要开辟1k个进程才能实现100万的并发连接,除了进程间上下文切换的时间消耗外,从内核/用户空间大量的fd结构内存拷贝,数组轮询等,是系统难以承受的。因此,基于select模型的服务器程序,要达到100级别的并发访问,是一个很难完成的任务。【除非是协程】
2.epoll原理以及优势
epoll的实现机制与select/poll机制完全不同,他们的缺点在epoll上不复存在。select/poll一般只能处理几千的并发连接。epoll通过在Linux内核中申请一个简易的文件系统。把原先的select/poll调用分为以下3个部分:
epoll_create
:在内核创建 epoll 实例(红黑树 + 就绪队列),返回管理该实例的 fd。epoll_ctl
:增删改红黑树节点(存储 fd 及关注事件),内核维护而非用户态数组。epoll_wait
:从就绪队列获取就绪事件,仅返回有事件的 fd,避免无效遍历。
epoll高效的原因如下:
- 数据结构优化:红黑树管理待检测 fd(O (log n) 增删),就绪队列存储就绪 fd(O (1) 获取)。
- 事件驱动:内核通过回调机制直接将就绪 fd 加入队列,无需遍历所有 fd,避免 select/poll 的 “盲目扫描”。
- 单次拷贝:仅拷贝就绪事件到用户态,非全量 fd,减少数据传输开销。
epoll_create在内核中创建的eventpoll结构如下:
struct eventpoll{//.../*红黑树的根节点,这棵树存储的是所有添加到epoll中需要监听的事件*/struct rb_root rbt;/*双链表【就绪队列】中则存放将要通过epoll_wait返回给用户的满足条件的事件*/struct list_head rdlist;//...
};
1.LT模式(水平触发,默认模式)
内核数据没被读完,就会一直上报数据。
- 触发条件:只要 fd 对应的读 / 写缓冲区有数据(未读完)或可写,就持续通知。
- 特点:类似 select/poll,允许分多次处理数据,编码简单,适合通用场景。
- 示例:recv 返回 > 0 时,可继续读取直到缓冲区空或阻塞(阻塞需谨慎)。
2.ET模式(边缘触发)
内核数据只上报一次。
- 触发条件:仅当 fd 状态发生变化(如缓冲区从无数据到有数据,或可写状态首次出现)时通知一次。
- 特点:强制要求一次性读尽数据(循环读至
EAGAIN
),fd 必须设为非阻塞,避免阻塞当前线程。 - 优势:减少重复通知,适合高并发、高吞吐量场景(如 Nginx),但编码复杂度高。
3.muduo采用的是LT
- 不会丢失数据或者消息
- 应用没有读取完数据,内核是会不断上报的
- 低延迟处理
- 每次读数据只需要一次系统调用,照顾了多个连接的公平性,不会因为某个连接上的数量量过大而影响其他连接处理消息。
- 跨平台处理
- 某些平台不支持ET模式下epoll模型,使用LT模式可以更好的跨平台处理。
7.moduo网络库编程
1.muduo源码编译安装
- 下载muduo源码
git clone https://github.com/chenshuo/muduo.git
- 安装boost开发库
- 安装cmake
- 修改CMakeLists.txt,注释掉单元测试,耽误时间
- 执行build.sh
./build.sh
- 再次
./build.sh
,显示100%完成即可。 - 再输入./build.sh install命令进行muduo库安装
- 去muduo-master同级目录下的build目录下的release-install-cpp11文件夹下将inlcude(头文件)和lib(库文件)目录下的文件拷贝到系统目录下,
mv muduo/ /usr/include/
,回到lib目录下,执行mv * /usr/local/lib/
,拷贝完成以后使用muduo库编写C++网络程序,不用在指定头文件和lib库文件路径信息了,因为g++会自动从/usr/include和/usr/local/lib路径下寻找所需要的文件。
g++ test.cpp -lmuduo_net -lmuduo_base -lpthread -std=c++11
,编译运行即可
2.muduo网络库服务器编程
muduo网络库给用户提供了两个主要的类
-
TcpServer:用于编写服务器程序的
-
TcpClient:用于编写客户端程序的
封装 epoll+线程池
好处:能够把网络I/O的代码【网络库封装】和业务代码区分开
网络库对外提供:用户的连接和断开,用户的可读写事件
基于muduo网络库开发服务器程序
- 组合TcpServer对象
- 创建EventLoop事件循环对象的指针
- 明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
- 在当前服务器类的构造函数当中,注册处理连接的回调函数和处理读写事件的回调函数
- 设置合适的服务端线程数量,muduo库会自己分配I/O线程和worker线程
/*
muduo网络库给用户提供了两个主要的类
TcpServer:用于编写服务器程序的
TcpClient:用于编写客户端程序的封装:epoll+线程池
好处:能够把网络I/O的代码【网络库封装】和业务代码区分开
网络库对外提供:用户的连接和断开,用户的可读写事件*/#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <functional>
#include <string>
using namespace std;
using namespace placeholders;
// 展开命名空间
using namespace muduo;
using namespace muduo::net;/*基于muduo网络库开发服务器程序
1.组合TcpServer对象
2.创建EventLoop事件循环对象的指针
3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
4.在当前服务器类的构造函数当中,注册处理连接的回调函数和处理读写事件的回调函数
5.设置合适的服务端线程数量,muduo库会自己分配I/O线程和worker线程
*/
class ChatServer
{
public:ChatServer(EventLoop *loop, // 事件循环const InetAddress &listenAddr, // Ip+Portconst string &nameArg) // 服务器的名字: _server(loop, listenAddr, nameArg), _loop(loop){// 给服务器注册用户的连接的创建和断开回调// 我知道断开连接怎么做,但是我不知道什么时候断开!所以需要回调!// 我们的方法除了this,还有一个参数,所以写_1_server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));// 给服务器注册用户读写事件回调_server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));// 设置服务器端的线程数量 1个I/O线程 3个worker线程_server.setThreadNum(4);}// 开启事件循环void start(){_server.start();}private:// 专门处理用户的连接创建和断开 epoll listenfd accept// 用户只要写回调就行,其余muduo管理了!void onConnection(const TcpConnectionPtr &conn){if (conn->connected()) // 连接成功{// 对端的cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << "state:online" << endl;}else{cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << "state:offline" << endl;conn->shutdown(); // close(fd)//_loop->quit(); //服务器退出}}// 专门处理用户的读写事件void onMessage(const TcpConnectionPtr &conn, // 连接Buffer *buffer, // 缓冲区Timestamp time) // 接收到数据的时间信息{string buf = buffer->retrieveAllAsString();cout << "recv data:" << buf << " time" << time.toString() << endl;// 收到啥就发啥conn->send(buf);}TcpServer _server; // #1EventLoop *_loop; // #2 epoll
};int main()
{EventLoop loop; // epollInetAddress addr("127.0.0.1", 8080); // 需要改的地方ChatServer server(&loop, addr, "CharServer"); // 可能需要改的地方server.start(); // listen epoll_ctl => epollloop.loop(); // epoll_wait以阻塞方式等待新用户连接,已连接用户的读写事件等return 0;
}
相关文章:
网络基础知识梳理和Muduo库使用
文章目录 网络基础知识梳理和Muduo库使用1.知识储备2.阻塞、非阻塞、同步、异步我的总结 3.Unix/Linux上的五种IO模型0.铺垫1.阻塞IO(blocking)2.非阻塞IO(non-blocking)3.IO复用(IO multiplexing)4.信号驱…...
IDEA 插件推荐:提升编程效率
通过安装和使用合适的插件,可以大幅提升开发效率和代码质量。本文将从多个维度推荐实用的 IDEA 插件,并提供安装与使用指南。 一、代码辅助类插件 1. Key Promoter X —— 快捷键学习利器 功能介绍:当你使用鼠标点击某个功能时,…...
001大模型-认识大模型以及大模型应用场景
大模型是一种基于海量数据训练的人工智能系统,具备强大的语言理解和生成能力。其工作原理是通过深度学习算法,分析大量文本数据,学习语言模式和知识,从而能够处理复杂的任务。大模型的应用广泛,包括自然语言处理、机器…...
Qt进阶开发:QTcpServer的的详解
文章目录 一、QTcpServer 简介二、常用成员函数的使用三、信号函数的使用四、虚函数的使用五、连接多客户端-服务端示例一、QTcpServer 简介 QTcpServer 是 Qt 网络模块中的一个核心类,用于实现 基于 TCP 协议的服务端(Server),它负责监听端口、接收客户端连接请求,并通过…...
Spark,集群搭建之Yarn模式
以下是Spark基于Yarn模式的集群搭建关键步骤(需先部署Hadoop Yarn集群): 一、环境准备 1. 确认Hadoop已运行 - 确保HDFS、Yarn ResourceManager和NodeManager正常启动。 2. 安装Java - 所有节点安装JDK 8,配置 JAVA_HOME 环境变量…...
fiddler 配置ios手机代理调试
平时做移动移动端开必的时候经常需要抓包手机,用于接口请求跟踪,但iOS的抓包经常性的配不成功,经过踩过不少坑后终于知道了整个配置流程,此文记录Fiddler抓包iOS手机的配置流程。 Step 1:Fiddler配置 通过工具栏Tool…...
iOS即时通信的技术要点
iOS即时通信开发的关键技术要点总结: 一、通讯协议选择 Socket通信 基础实现:使用原生BSD Socket或CFNetwork框架(复杂),推荐第三方库如CocoaAsyncSocket(封装GCDAsyncSocket),简化T…...
Windows 安装 Milvus
说明 操作系统:Window 中间件:docker desktop Milvus:Milvus Standalone(单机版) 安装 docker desktop 参考:Window、CentOs、Ubuntu 安装 docker-CSDN博客 安装 Milvus 参考链接:Run Mil…...
5G网络:能源管理的“智能电网“革命,Python如何成为关键推手?
5G网络:能源管理的"智能电网"革命,Python如何成为关键推手? 大家好,我是Echo_Wish。今天咱们聊一个既硬核又接地气的话题——5G网络如何用Python代码重构全球能源管理。 不知道你们有没有注意过: • 家里装…...
解决WSL、Ubuntu的.ico图标不正确显示缩略图
解决WSL、Ubuntu的.ico图标不正确显示缩略图 问题描述 Win10系统中由于更新了某些软件,篡改了默认的图像显示软件,导致WSL等软件未能成功显示图标,表现如下: 解决方法 将ico文件的默认打开方式更改为“画图”,如下…...
Redis+Caffeine构造多级缓存
一、背景 项目中对性能要求极高,因此使用多级缓存,最终方案决定是RedisCaffeine。其中Redis作为二级缓存,Caffeine作为一级本地缓存。 二、Caffeine简单介绍 Caffeine是一款基于Java 8的高性能、灵活的本地缓存库。它提供了近乎最佳的命中…...
Redis+Caffeine构建高性能二级缓存
大家好,我是摘星。今天为大家带来的是RedisCaffeine构建高性能二级缓存,废话不多说直接开始~ 目录 二级缓存架构的技术背景 1. 基础缓存架构 2. 架构演进动因 3. 二级缓存解决方案 为什么选择本地缓存? 1. 极速访问 2. 减少网络IO 3…...
【机器人】复现 UniGoal 具身导航 | 通用零样本目标导航 CVPR 2025
UniGoal的提出了一个通用的零样本目标导航框架,能够统一处理多种类型的导航任务。 支持 对象类别导航、实例图像目标导航和文本目标导航,而无需针对特定任务进行训练或微调。 本文分享UniGoal复现和模型推理的过程~ 查找沙发,模…...
LeetCode 373 查找和最小的 K 对数字题解
LeetCode 373 查找和最小的 K 对数字题解 题目描述 给定两个以升序排列的整数数组 nums1 和 nums2,以及一个整数 k。定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。请找到和最小的 k 个数对。 解题思路 最小堆优化法…...
搜索二维矩阵 II 算法讲解
搜索二维矩阵 II 算法讲解 一、问题描述 给定一个 m x n 的二维矩阵 matrix ,需要在其中搜索一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。每列的元素从上到下升序排列。要求编写一个高效的算法来完成搜索任务。 二、解题思路 方法一:暴力枚举 …...
三层交换机,单臂路由(用DHCP自动配置ip+互通+ACL
三层交换机,单臂路由(用DHCP自动配置ip互通ACL 任务 1.用DHCP自动配置ip 2.三层交换机SVI、 3.单臂路由 4.互通 5.ACL三层交换机SVI 交换机 Switch>en Switch#conf t Enter configuration commands, one per line. End with CNTL/Z. Switch(conf…...
OpenCV CUDA 模块中在 GPU 上对图像或矩阵进行 翻转(镜像)操作的一个函数 flip()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::cuda::flip 是 OpenCV 的 CUDA 模块中的一个函数,用于在 GPU 上对图像或矩阵进行 翻转(镜像)操作。它类似…...
链表面试题7之相交链表
来了来了,这道题才是值得我们奇思妙想的题,链接在下面。 160. 相交链表 - 力扣(LeetCode) 看完题目一脸懵吗,没关系,我们还得看示例 还是一脸懵怎么办?? 两个链表相交的方式有几种?…...
Excel-to-JSON插件专业版功能详解:让Excel数据转换更灵活
前言 在数据处理和系统集成过程中,Excel和JSON格式的转换是一个常见需求。Excel-to-JSON插件提供了一套强大的专业版功能,能够满足各种复杂的数据转换场景。本文将详细介绍这些专业版功能的应用场景和使用方法。 订阅说明 在介绍具体功能之前…...
【C++】”如虎添翼“:模板初阶
泛型编程: C中一种使用模板来实现代码重用和类型安全的编程范式。它允许程序员编写与数据类型无关的代码,从而可以用相同的代码逻辑处理不同的数据类型。模板是泛型编程的基础 模板分为两类: 函数模板:代表了一个函数家族&#x…...
【K8S学习之探针】详细了解就绪探针 readinessProbe 和存活探针 livenessProbe 的配置
参考 Pod健康检查 Kubernetes 学习笔记Kubernetes 就绪探针(Readiness Probe) - 人艰不拆_zmc - 博客园Kubernetes存活探针(Liveness Probe) - 人艰不拆_zmc - 博客园 Pod健康检查 Pod的健康状态由两类探针来检查:…...
WSL 安装 Debian 12 后,Linux 如何安装 redis ?
在 WSL 的 Debian 12 上安装 Redis 的步骤如下: 1. 更新系统包列表 sudo apt update && sudo apt upgrade -y2. 安装 Redis sudo apt install redis-server -y3. 启动 Redis 服务 sudo systemctl start redis4. 设置开机自启 sudo systemctl enable red…...
python打卡day22
复习日 仔细回顾一下之前21天的内容,没跟上进度的同学补一下进度。 作业: 自行学习参考如何使用kaggle平台,写下使用注意点,并对下述比赛提交代码 kaggle泰坦里克号人员生还预测 就是很简单很草率地走了一遍机器学习的经典流程&am…...
国产化Excel处理控件Spire.XLS系列教程:如何通过 C# 删除 Excel 工作表中的筛选器
在 Excel 文件中,筛选器(Filter)是一个常用的数据处理工具,可以帮助用户快速按条件筛选数据行。但在数据整理完成、导出、共享或打印之前,往往需要 删除 Excel 工作表中的筛选器,移除列标题中的下拉筛选按钮…...
使用 DMM 测试 TDR
TDR(时域反射计)可能是实验室中上升时间最快的仪器,但您可以使用直流欧姆表测试其准确性。 TDR 测量什么 在所有高速通道中,反射都很糟糕。我们尝试设计一个通道来减少反射,这些反射都会导致符号间干扰 (…...
基于卡尔曼滤波的传感器融合技术的多传感器融合技术(附战场环境模拟可视化代码及应用说明)
基于卡尔曼滤波的传感器融合技术的多传感器融合技术(附战场环境模拟可视化代码及应用说明) 1 目标运动状态空间建模1.1 状态向量定义1.2 状态转移方程1.3 观测模型构建2 卡尔曼滤波核心算法实现2.1 初始化2.2 预测步骤2.3 更新步骤3 多传感器融合仿真验证3.1 传感器模型模拟3…...
M8040A/M8199助力数据中心收发信机测试
随着数字通信和大数据的不断发展,误码率测试变得越来越重要。高性能误码率测试仪作为一种关键的测试设备,可以对数字信号进行高速、高精度的误码率测试,广泛应用于通信、数据中心、半导体等行业。 M8040A误码仪系统当前不仅在上游IP和顶层芯…...
傲云源墅:以五傲价值重构北京主城别墅格局
在高端别墅市场中,产品自身的品质与特色是吸引客户的关键。北京傲云源墅以其独特的 “五傲” 价值,重新定义了北京主城别墅的标准。 首先是低密之傲,傲云源墅的容积率低至约 0.9,与市场上 1.0 以上容积率的别墅相比,为…...
精益数据分析(56/126):创业阶段的划分与精益数据分析实践
精益数据分析(56/126):创业阶段的划分与精益数据分析实践 在创业和数据分析的探索之旅中,理解创业阶段的划分以及与之对应的精益数据分析方法至关重要。今天,依旧怀揣着与大家共同进步的心态,深入研读《精…...
[redis进阶六]详解redis作为缓存分布式锁
目录 一 什么是缓存 缓存总结板书: 二 使⽤Redis作为缓存 三 缓存的更新策略 1) 定期⽣成 2) 实时⽣成 四 面试重点:缓存预热,缓存穿透,缓存雪崩 和缓存击穿 1)缓存预热 2)缓存穿透 3)缓存雪崩 4)缓存击穿 五 分布式锁 板书: 1)什么是分布式锁 2)分布式锁的基…...
【RabbitMQ】应用问题、仲裁队列(Raft算法)和HAProxy负载均衡
🔥个人主页: 中草药 🔥专栏:【中间件】企业级中间件剖析 一、幂等性保障 什么是幂等性? 幂等性是指对一个系统进行重复调用(相同参数),无论同一操作执行多少次,这些请求…...
国产密码新时代!华测国密 SSL 证书解锁安全新高度
在数字安全被提升到国家战略高度的今天,国产密码算法成为筑牢网络安全防线的关键力量。华测国密SSL证书凭借其强大性能与贴心服务,为企业网络安全保驾护航,成为符合国家安全要求的不二之选! 智能兼容,告别浏览器适配…...
【Linux篇章】Linux 进程信号2:解锁系统高效运作的 “隐藏指令”,开启性能飞跃新征程(精讲捕捉信号及OS运行机制)
本篇文章将以一个小白视角,通俗易懂带你了解信号在产生,保存之后如何进行捕捉;以及在信号这个话题中;OS扮演的角色及背后是如何进行操作的;如何理解用户态内核态;还有一些可以引出的其他知识点;…...
C# 基础 try-catch代码块
try-catch代码块是C#中用于异常处理的核心机制。异常是在程序执行过程中可能出现的错误,而try-catch代码块允许您在执行代码时捕获并处理这些异常。 一、基础结构 try {//可能抛出异常的代码 } catch (ArgumentException ex) {//处理特定异常 } catch (Excepti…...
为什么 mac os .bashrc 没有自动加载?
原因说明 在macOS中,默认情况下,终端使用的是Bash或Zsh作为shell。对于较新版本的macOS(从Catalina开始),默认的shell已经切换为Zsh。因此,如果你正在使用Zsh,.bashrc文件不会自动生效…...
【HarmonyOS Next之旅】DevEco Studio使用指南(二十二)
目录 1 -> 开发静态共享包 1.1 -> 创建库模块 1.2 -> 编译库模块 2 -> 开发动态共享包 2.1 -> 使用约束 2.2 -> 开发动态共享包 2.2.1 -> 创建HSP模块 2.2.2 -> 编译HSP模块 3 -> 发布共享包 1 -> 开发静态共享包 HAR(Harmony Archive…...
QT6.8安装教程
官网下载 链接: Index of /official_releases/online_installers 这个比较慢 建议去 清华大学开源软件镜像站:Index of /qt/archive/online_installers/4.9/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 根据自己什么系统选择 点击打开…...
【Rust泛型】Rust泛型使用详解与应用场景
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
一周学完计算机网络之三:1、数据链路层概述
简单的概述 数据链路层是计算机网络体系结构中的第二层,它在物理层提供的基本服务基础上,负责将数据从一个节点可靠地传输到相邻节点。可以将其想象成一个负责在两个相邻的网络设备之间进行数据 “搬运” 和 “整理” 的 “快递中转站”。 几个重要概念…...
配置ssh无密登录
在root下有一个.ssh文件夹,它的下面有一个known_hosts文件,这个里面记录了哪些其他的主机通过ssh访问过当前的主机。 免密登录原理 (2)生成公钥和私钥 具体操作: 1. 进入 hadoop1001 2. 运行命令:ssh-keyg…...
南京邮电大学金工实习答案
一、金工实习的定义 金工实习是机械类专业学生一项重要的实践课程,它绝非仅仅只是理论知识在操作层面的简单验证,而是一个全方位培养学生综合实践能力与职业素养的系统工程。从本质上而言,金工实习是学生走出教室,亲身踏入机械加…...
无偿帮写毕业论文
以下教程教你如何利用相关网站和AI免费帮你写一个毕业论文。毕竟毕业论文只要过就行,脱产学习这么多年,终于熬出头了,完成毕设后有空就去多看看亲人好友,祝好! 一、找一个论文模板(最好是overleaf) 废话不多说&#…...
【高数上册笔记01】:从集合映射到区间函数
【参考资料】 同济大学《高等数学》教材樊顺厚老师B站《高等数学精讲》系列课程 (注:本笔记为个人数学复习资料,旨在通过系统化整理替代厚重教材,便于随时查阅与巩固知识要点) 仅用于个人数学复习,因为课…...
大数据从专家到小白
文章目录 数据湖技术Apache Iceberg FlinkHiveHadoopHDFS 数据湖技术 Apache Iceberg Iceberg是一个通用的表格式(数据组织格式),它可以适配Presto,Spark等引擎提供高性能的读写和元数据管理功能。 Flink Hive Hadoop HDFS...
特励达力科LeCroy推出Xena Freya Z800 800GE高性能的800G以太网测试平台
Xena Freya Z800 800GE 是由全球领先的测试与测量解决方案提供商特励达力科公司(Teledyne LeCroy)开发的高性能以太网测试平台,专为满足从10GE到800GE数据中心互连速度的需求而设计。特励达力科公司在网络测试领域拥有超过50年的技术积累&…...
LeetCode 热题 100 98. 验证二叉搜索树
LeetCode 热题 100 | 98. 验证二叉搜索树 大家好,今天我们来解决一道经典的二叉树问题——验证二叉搜索树。这道题在 LeetCode 上被标记为中等难度,要求判断给定的二叉树是否是一个有效的二叉搜索树(BST)。 问题描述 给你一个二…...
Linux文件编程——open函数
在 Linux 系统中,文件操作不仅仅通过高级语言的标准库进行,底层的文件操作是通过 系统调用 来实现的。系统调用 是用户空间与操作系统内核之间的接口,允许程序请求操作系统提供的服务,包括文件读写、内存管理、进程控制等。本文将…...
Linux-Ext系列文件系统
1.理解硬件 1.1磁盘 机械磁盘是计算机中唯⼀的⼀个机械设备 磁盘---外设 慢 容量⼤,价格便宜 1.2磁盘的物理结构 1.3磁盘的存储结构 扇区:是磁盘存储数据的基本单位,512字节,块设备 如何定位⼀个扇区呢? 可以先定…...
Multisim14使用教程详尽版--(2025最新版)
一、Multisim14前言 1.1、主流电路仿真软件 1. Multisim:NI开发的SPICE标准仿真工具,支持模拟/数字电路混合仿真,内置丰富的元件库和虚拟仪器(示波器、频谱仪等),适合教学和竞赛设计。官网:艾…...
C——猜数字游戏
前面我们已经学习了C语言常见概念,数据类型和变量以及分置于循环的内容,现在我们可以将这些内容结合起来写一个有趣的小游戏。下面正式开始我们今天的主题——猜数字游戏的实现。 猜数字游戏的要求: 1.电脑自动生成1~100的随机数。 2.玩家…...