1.单例模式
单例模式在一个项目中,全局范围内,某个类的实例有且仅有一个,通过这个唯一的实例向其他模块提供数据的全局访问,这种模式就叫单例模式。 为什么不使用全局变量而是使用单例代替全局变量?直接使用全局变量会破坏类的封装,访问权限不受限制,任意位置的任意模块都可以对全局变量进行读写操作,在一处对全局变量进行修改可能会影响到其他模块正常运行 单例模式的类的创建C++中创建一个实例对象是通过new来操作,其本质上是调用了这个类的构造函数 三种构造函数 默认构造函数:创建一个新的对象,单例模式中需要处理掉 拷贝构造函数:根据已有对象拷贝出一个新的对象,单例模式中需要处理掉 移动构造函数:参数为本类右值引用^右值引用的构造函数(&&),转移右值对象的资源, 因其本质是资源的转移(对象A的资源转移给对象B),还是只有一份实例,所以单例模式中移动构造函数可以存在。 单例模式中对默认构造函数和拷贝构造函数的处理1.将默认构造函数和拷贝构造函数的权限设置为私有的 123456class TaskQueue{private: TaskQueue(){} Ta...
7.Reactor
Reactor一、Reactor 解决的核心问题在高并发场景下,传统的 “一个连接一个线程” 模型会因为线程上下文切换和资源耗尽而崩溃。 Reactor 的核心思路是: 用单线程(或少量线程)监听所有 IO 事件,事件就绪后再分发给业务逻辑处理,从而避免无效的线程切换和资源浪费。 它的本质是事件驱动 + IO 多路复用的结合。 二、Reactor 的核心组件一个完整的 Reactor 模式包含 5 个核心组件,协同工作: 组件 职责 实现方式 Reactor 事件循环的核心,负责管理事件注册、监听和分发 封装 epoll/kqueue 等多路复用器 多路复用器(Demultiplexer) 等待 IO 事件就绪,是 Reactor 的底层依赖 Linux 用 epoll,BSD 用 kqueue,Windows 用 IOCP 事件处理器(Handler) 绑定到特定的 IO 事件,执行具体的业务逻辑 如 ReadHandler、WriteHandler Acceptor 专门处理新连接事件的 Handler,接受连接后为新 socket 注册...
6.IO多路复用-epoll
epoll一、核心背景在高并发网络编程中(比如百万连接的服务器),传统的 select/poll 会遇到三个致命问题: 性能瓶颈:每次调用都要遍历所有监听的文件描述符(FD),FD 越多越慢(O (n)); 数量限制:select 最多监听 1024 个 FD(FD_SETSIZE 限制); 数据拷贝:每次调用都要把用户态的 FD 集合拷贝到内核态,开销极大。 epoll 就是为解决这些问题而生的 —— 它是 Linux 内核专为高并发 I/O 场景设计的 “事件通知管家”,核心是「只关注有变化的 FD」,让服务器能高效处理数万甚至数百万的并发连接。 通俗类比 select/poll:像一个老师,每天挨个检查全班 1000 个学生的作业(不管有没有写完),效率极低; epoll:像一个班长,只有学生写完作业(FD 就绪)才主动告诉老师,老师只处理这些 “写完作业的学生”,效率直接拉满。 二、epoll 核心底层原理epoll 的高效,本质是内核用了三个关键设计,我们逐一拆解: 1. 核心数据结构:红黑树 + 就绪链表内核为每个 epoll 实例维护两个核...
5.IO多路复用-poll
pollpoll使用相对较少,跨平台推荐select,高并发推荐epoll 一、poll 核心概念poll 是 Linux 下另一种多路复用 I/O 模型,与你之前学习的 select 功能类似(监控多个文件描述符的事件),但解决了 select 的部分缺陷,是网络编程中实现多客户端并发的常用方案。 1.1 与 select 的核心区别(对比你的 select 代码) 特性 select poll 文件描述符集合存储 固定大小的位图(fd_set) 动态的结构体数组(pollfd) 最大监控描述符限制 受限于 FD_SETSIZE(默认 1024) 无硬限制,仅受系统资源约束 事件重置 每次需重新初始化集合 无需重置,事件结果存在 revents 中 参数传递 值传递(会修改原集合) 结构体数组(输入输出分离) 1.2 核心优势 突破 select 最大 1024 个文件描述符的限制; 无需像 select 那样每次循环重置文件描述符集合; 支持更多类型的事件监控(如普通读、带外数据读、出错等)。 二、poll 核心 API 详解2.1 头文...
4.IO多路复用-select
IO多路复用IO 多路复用是一种让单个线程(或少量线程)能够同时监听多个文件描述符(File Descriptor,FD,比如网络连接、文件、管道)的技术,当某个 FD 有可读 / 可写事件发生时,系统会通知程序去处理对应的 IO 操作。 它解决的核心问题是:避免线程 / 进程阻塞在单个 IO 操作上,提升程序处理大量并发 IO 的能力(比如高并发的服务器)。 IO 多路复用的三种核心实现(Linux 下) 方式 特点 适用场景 select 监听的 FD 数量有限(默认 1024),每次调用需要拷贝 FD 集合,效率低 兼容性好,低并发场景 poll 突破 FD 数量限制,但仍需遍历所有 FD,高并发下效率一般 中等并发,需要兼容多系统 epoll 基于事件驱动,只处理有事件的 FD,无 FD 数量上限,效率最高 高并发场景(如百万连接) select函数原型select 是 IO 多路复用的基础实现,内部基于线性表实现的,核心作用是委托内核批量检测多个文件描述符(fd)的读写 / 异常状态,且具备跨平台特性(Linux...
3.端口复用
端口复用一、端口复用解决了什么问题?在讲解具体用法前,先明确端口复用的核心价值 —— 它主要解决两类高频的 “端口占用” 问题: 问题 1:服务重启时提示 “Address already in use” 默认情况下,当你关闭一个 TCP 服务端(比如 epoll 服务)后,端口不会立即释放,而是会进入 TIME_WAIT 状态(通常持续 2-4 分钟)。此时如果立即重启服务,内核会提示: 1bind failed: Address already in use 这是因为内核认为该端口还被 “旧连接” 占用,不允许新进程绑定。 问题 2:多进程 / 多线程绑定同一端口(如负载均衡) 某些场景下(比如 Nginx 多进程、多线程服务),需要让多个进程 / 线程同时监听同一个端口,默认情况下内核会拒绝,而端口复用可以允许这种操作。 二、端口复用的核心原理端口复用的核心是设置套接字选项 SO_REUSEADDR,它会修改内核对 TCP 端口的绑定规则: 允许绑定处于 TIME_WAIT 状态的端口:跳过 “端口被 TIME_WAIT 连接占用” 的检查; 允许多...
2.socket编程
这篇文章讲了 socket 编程的基础流程,包括客户端和服务端的交互过程 socket编程 通信测试代码服务端1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283#include<unistd.h> // 提供read/write/close等系统调用#include<stdio.h> // 标准输入输出#include<stdlib.h> // 标准库(exit等)#include<string.h> // 字符串操作(memset等)#include<stdint.h> // 整型类型(uint16_t等)#include<arpa/inet.h> // 网络编程(inet_ntop/ht...
1.字节序和IP地址转换
字节序1. 字节序是什么?(通俗理解)字节序(Endianness)指的是多字节数据在内存中的存储顺序。 计算机存储数据时,单个字节(如 0x12)没有顺序问题,但多字节数据(如 16 位端口号 0x1234、32 位 IP 地址 0x12345678)会有两种存储方式: 把高位字节存在低内存地址(大端) 把低位字节存在低内存地址(小端) 1. 大端序(Big-Endian):“高位在前”(符合人类习惯) 规则:高位字节存在低地址内存格,低位字节存在高地址内存格; 比喻:像人类写数字 1234 一样,先写高位的12,再写低位的34; 例子:存储 0x1234(十进制 4660) 内存地址 存储内容 说明 100 0x12 低地址存高位字节 101 0x34 高地址存低位字节 2. 小端序(Little-Endian):“低位在前”(计算机更常用) 规则:低位字节存在低地址内存格,高位字节存在高地址内存格; 比喻:把数字倒着写,先写低位的34,再写高位的12; 例子:存储 0x1234(十进制 4660) 内存地址 存储内容 说明 1...
11.enable_if
enable_if一、std::enable_if 核心定义std::enable_if 是 C++11 引入的模板元编程工具,本质是条件编译模板,核心作用是: 根据一个编译期布尔条件,决定是否 “启用” 某个模板(函数 / 类); 底层完全依赖 SFINAE 规则:条件为 false 时,enable_if 的 type 成员不存在 → 模板替换失败,编译器跳过该版本;条件为 true 时,type 存在 → 模板正常启用。 官方定义(简化版)1234567891011template <bool B, typename T = void>struct enable_if {}; // 条件B为false时,无type成员template <typename T>struct enable_if<true, T> { // 条件B为true时,定义type成员 using type = T;};// 常用别名(简化写法)template <bool B, typename T ...
10.SFINAE
SFINAE一、SFINAE 核心定义SFINAE 直译是「替换失败不是错误」,是 C++ 模板重载解析阶段的关键规则: 当编译器尝试将模板参数替换为具体类型时,如果出现 “语法合法但替换失败” 的情况,不会直接报错,而是跳过这个模板重载版本,继续尝试其他可行的版本; 只有当所有模板重载版本都替换失败,且无其他非模板重载可用时,编译器才会抛出真正的编译错误。 通俗理解(无比喻版)模板重载就像 “多套备用方案”,编译器会逐个检查方案是否适配当前类型: 某套方案因类型不匹配导致替换失败 → 放弃这套方案,看下一套; 所有方案都适配失败 → 才报错。 二、核心原理:模板替换阶段 vs 编译阶段SFINAE 只作用于模板参数替换阶段,而非后续的语义分析 / 编译阶段,这是关键: 阶段 行为 SFINAE 是否生效 模板参数替换阶段 编译器将实参类型代入模板形参,检查语法是否合法(如成员是否存在、类型是否匹配) 生效(失败则跳过) 语义分析 / 编译阶段 检查代码逻辑(如变量未定义、函数调用错误) 不生效(直接报错) 三、SFINAE 的典型...