- 博客(16)
- 收藏
- 关注
原创 TIME_WAIT详解
在 TCP 四次挥手中,主动关闭方发送完最后一个确认包(ACK)后,并不知道对方是否收到了。如果 ACK 丢失,被动关闭方会超时并重传最后的 FIN 包。如果此时主动方已经彻底关闭连接,它将无法响应这个 FIN,导致对方无法正常关闭。TIME_WAIT允许主动方在窗口期内重发 ACK。客户端 → 服务端:FIN(我发完了)服务端 → 客户端:ACK(收到你的FIN)服务端 → 客户端:FIN(我也发完了)客户端 → 服务端:ACK(收到你的FIN,连接可以关闭了)
2025-12-26 16:01:37
918
原创 AVL树详解
AVL树本质上是二叉搜索树(BST):左子树所有节点的值 < 根节点值 < 右子树所有节点的值。平衡条件:每个节点的左子树高度和右子树高度之差的绝对值(称为平衡因子,Balance Factor)不超过1。即 |height(left) - height(right)| ≤ 1。平衡因子可能的值:-1、0、+1。由于严格保持平衡,AVL树的查找、插入、删除操作的时间复杂度均为O(log n),在最坏情况下也不会退化成链表(普通BST的最坏情况是O(n))。
2025-12-25 20:58:54
241
原创 BST树详解
对于树中的每一个节点X其左子树的所有节点值小于X 的值。其右子树的所有节点值大于X 的值。左右子树本身也必须是二叉搜索树(递归定义)。节点通常包含:值(key)、左孩子指针、右孩子指针(有时还有父指针)。左边的树是BST树,右边的树不是。
2025-12-25 20:38:24
520
原创 TCP(2)
第二次握手丢失是最浪费资源的情况,因为它迫使通信双方都在不断尝试重发。阶段现象结果客户端 (Client)状态变为FIN_WAIT_1,没收到 ACK超时重传FIN 包;若多次重传失败,直接强制关闭。服务端 (Server)没收到 FIN 包状态保持;直到保活探测超时或收到 RST 后才关闭。第一次挥手丢失并不可怕,客户端会通过“反复横跳”(重传)来尝试修复;如果实在连不上,客户端会自己先“撒手不管”(直接关闭),而服务端最终也会因为超时而释放资源。视角认知反应客户端“我的 FIN 丢了吧?
2025-12-24 22:24:37
644
1
原创 重载、重写与隐藏
解决隐藏只有两个办法:using Base::func;或者 Base::func() 显式调用。隐藏是派生类只要定义了同名函数(不管参数),就把基类所有同名函数全部遮蔽的名称查找规则。隐藏的本质是“名称查找发生在重载解析之前”,找到派生类的名字后就不再往基类继续找了。重写是继承体系中同名同参、基类加virtual的运行期多态。重载是同一作用域、同名不同参的编译期多态。
2025-12-24 13:51:02
231
原创 HTTP详解
HTTP 是互联网上最基础、最重要的应用层协议,用于在客户端(浏览器、App)和服务器之间传输超文本数据(如 HTML 文件、图片、视频、JSON 等)。├─→ 有 Cache-Control: max-age=xxx 或 Expires → 未过期 → 直接用缓存(200 from cache)的(Stateless):服务器不默认记住客户端上次请求是什么,每次请求都是独立的(后面会讲怎么解决这个问题)├─→ 带 If-None-Match(ETag)或 If-Modified-Since。
2025-12-22 21:43:12
713
原创 TCP详解
给迟到的 FIN 包留出重传时间让被动关闭方有足够时间收到 ACK,避免它一直处于 FIN_WAIT_2 或重传状态。六、为什么TCP可靠?
2025-12-22 21:08:46
862
原创 IO复用:epoll
时间复杂度优秀select/poll:每次调用都需要把整个关注的文件描述符集合(fd set)从用户态拷贝到内核态,并且内核需要线性扫描整个集合来找出哪些 fd 就绪,时间复杂度是 O(n)。epoll:只需要在初次注册兴趣事件时(epoll_ctl)拷贝一次,之后每次 epoll_wait 调用时,内核直接返回已经就绪的事件列表,时间复杂度接近 O(1)(实际上是 O(就绪事件数量)),不需要再扫描全部 fd。文件描述符数量限制极高。
2025-12-21 21:27:37
674
原创 IO复用:poll
poll() 是 level-triggered(水平触发)的:如果事件未处理,下次 poll() 仍会报告它。当网卡收到包 → tcp_data_queue() → sock_def_readable() → wake_up_interruptible(&sk->sk_sleep)。注意:poll() 会阻塞调用线程,直到超时或事件发生。poll() 调用时,内核会复制 fds 数组到内核空间,然后检查每个 fd 的状态。进程被唤醒后回到 do_poll(),再来一轮遍历检查谁就绪了。
2025-12-21 20:14:01
926
原创 线程池(3):工作窃取线程池WorkingStealingPool
核心设计是:每个工作线程绑定独立的任务队列,线程优先处理自身队列中的任务,当自身队列空时,主动从其他线程的任务队列 “窃取” 任务执行 —— 本质是通过负载均衡提升线程利用率,适配 “任务粒度不均、多线程并行执行” 的场景。1.解决 “负载不均” 导致的资源浪费问题。2.解决 “任务粒度不均” 的并行效率问题。3.解决 “共享队列锁竞争” 的性能问题。1.WorkingStealingPool的定义。2.WorkingStealingPool的需求。2. 任务粒度不均的场景。3. 高并发低锁竞争场景。
2025-12-03 19:32:44
159
原创 线程池(2):缓存线程池CachedThreadPool
缓存线程池是,核心设计围绕 “” 展开 —— 没有固定的核心线程数(或核心线程数为 0),当有新任务提交时,若无空闲线程则创建新线程执行,线程空闲超过指定时间(默认通常 60 秒)则自动销毁,最终线程池的线程数会随任务量动态伸缩。它的设计初衷是解决 “短期任务、高并发峰值、任务执行时间不可预测” 的场景痛点,平衡并发效率和资源占用。
2025-12-02 21:14:25
193
原创 线程池(1):固定线程池FixedThreadPool
线程池是一种—— 预先创建一定数量的线程(核心线程),将待执行的任务提交到任务队列,线程池中的线程循环从队列中获取任务并执行,任务完成后线程不销毁,而是回到线程池等待下一个任务,解决频繁创建 / 销毁线程的开销和并发控制问题。
2025-12-02 21:04:05
666
原创 结构体(总结)
结构体是一种数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要储存空间。结构体的初始化在定义后,可以直接利用{ }进行逐一赋值(按照顺序),或者利用点(.)访问进行赋值,也可以利用指针(->)进行逐个赋值(后面会说的)。例如,我们定义一个结构体并进行初始化。
2024-05-12 16:50:08
1028
1
原创 指针(总结)
为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号一 样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。定义一个指针变量如果不指向另一个变量的话,一定要赋予空(NULL),不然会变成野指针,会很危险。计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如。c/c++中根据*的位置和环境的不同,*代表着不同的含义。指针的大小在32位平台是4个字节,在64位平台是8个字节。(1)在数学中*的含义是乘法。b指向a,通过a的地址而获取到a空间中的值。三、一级指针及多级指针。
2024-05-08 16:36:20
203
2
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅