消息缓冲区 MsgBuffer

第 2 课:消息缓冲区 MsgBuffer 对应源文件: trantor/utils/MsgBuffer.h / MsgBuffer.cc — 核心读写缓冲区 trantor/net/inner/BufferNode.h — 发送队列多态节点 一、为什么需要 MsgBuffer? TCP 是流式协议,recv() 一次调用不一定能读完一个完整消息,也可能读到多个消息粘在一起(粘包)。 需要一个弹性缓冲区来: 接收数据时:把内核 socket 缓冲区的数据读进来,等凑够一个完整包再交给上层 发送数据时:把待发送数据先攒在缓冲区,等 socket 可写时分批发出 支持在头部预留空间(prepend),方便后填消息长度字段 二、内存布局 2.1 物理结构 1 2 3 4 5 6 7 8 9 buffer_ (std::vector<char>,初始大小 = 2048 + 8) 索引: 0 8 tail_ buffer_.size() │ │ │ │ ▼ ▼ ▼ ▼ [prepend区][─── 可读数据 ───][──── 可写空间 ────] └── 8字节 ┘ ↑ ↑ head_ tail_ prepend 区 [0, head_):保留 8 字节,用于在数据头部插入字段(不需要移动数据) 可读区 [head_, tail_):已接收但未被消费的数据,大小 = tail_ - head_ 可写区 [tail_, buffer_.size()):空闲空间,大小 = buffer_.size() - tail_ 2.2 关键常量与初始状态 1 2 3 4 5 6 7 8 9 // MsgBuffer.cc 第 31 行 static constexpr size_t kBufferOffset{8}; // prepend 预留大小 // 构造函数(MsgBuffer.cc 第 34-37 行) MsgBuffer::MsgBuffer(size_t len) : head_(kBufferOffset), // head_ 从 8 开始 initCap_(len), // 记录初始容量,用于 retrieveAll 的缩容 buffer_(len + head_), // 总容量 = 用户要求 + 8字节 prepend tail_(head_) // tail_ 也从 8 开始,初始可读字节为 0 初始状态(len = 2048): ...

April 2, 2026 · 9 min · 1791 words

trantor 日志系统

第 1 课:trantor 日志系统 对应源文件: trantor/utils/LogStream.h — 底层缓冲区 + 流写入 trantor/utils/Logger.h — 核心日志类 + 所有宏定义 trantor/utils/AsyncFileLogger.h — 异步文件写入 一、整体架构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 用户代码: LOG_INFO << "玩家登录" << playerId; │ ▼ [Logger 对象 (临时变量)] 构造时:记录时间/文件名/行号/级别 .stream() 返回 LogStream& │ ▼ [LogStream 对象] operator<< 链式写入 数据落入 FixedBuffer (4000字节栈内存) │ ▼ [Logger 析构时] 调用 outputFunc_(index)(buf, len) 默认 → fwrite(stdout) 生产环境 → AsyncFileLogger::output() 核心思想:Logger 是一个临时对象,构造写头,析构输出,<< 运算符把数据攒进缓冲区。整个过程利用 C++ 的 RAII 机制自动完成,用户只需一行代码。 ...

April 1, 2026 · 7 min · 1444 words

DeerFlow 2.0 本地部署与排坑实战指南

🦌 DeerFlow 2.0 本地化部署与排坑实战指南 文档维护: Hical 适用环境: Windows + Docker Desktop (企业内网管控环境) 📌 项目简介 DeerFlow 是一个强大的多智能体(Multi-Agent)协作框架,专为长时间运行的复杂自主任务设计(如自动化编码、深度调研、排障分析)。底层基于 LangGraph,支持沙盒(Sandbox)隔离执行。 🛠️ 部署前置准备 由于公司终端管控策略(如 IP-Guard 等防泄密软件)可能会禁用系统 WSL (Windows Subsystem for Linux) 或拦截 C 盘挂载,建议 Docker Desktop 配置如下: 禁用 WSL:若启动 Docker 报错,修改 %APPDATA%\Docker\settings.json,将 "wslEngineEnabled" 改为 false,强制使用 Hyper-V 引擎。 准备代码: 1 2 3 git clone https://github.com/bytedance/deer-flow.git cd deer-flow ⚙️ 核心配置修改 (避坑指南) 为了防止在启动和编译过程中出现各种“水土不服”的报错,在执行启动命令前,请务必完成以下 5 步修改: 配置根目录 .env:复制 .env.example 重命名为 .env,并在末尾追加以下关键变量: 1 2 3 4 5 6 # 大模型 Token ANTHROPIC_API_KEY=XXXXXX # 必须配置 Auth 组件的 Base URL,否则前端 SSR 渲染会报 500 错误!(端口固定为 2026) BETTER_AUTH_BASE_URL=http://localhost:2026 BETTER_AUTH_SECRET=glacier_network_super_secret_key_2026 配置大模型 config.yaml:复制 config.example.yaml 重命名为 config.yaml,配置内网模型: models: name: claude-sonnet-4-6 display_name: Claude Sonnet 4.6 (Claude Code OAuth) use: langchain_anthropic:ChatAnthropic model: claude-sonnet-4-6 api_key: $ANTHROPIC_API_KEY max_tokens: 8192 记得把系统默认的模型指向刚才配置好的这个内网模型 default_model: claude-sonnet-4-6 ...

March 25, 2026 · 8 min · 1579 words

极客专属博客搭建全记录

🚀 极客专属博客搭建全记录 (Hugo + GitHub Actions) 技术栈:Hugo (Extended版) + GitHub Pages + GitHub Actions CI/CD 主题:PaperMod (极简名片风 / 深色模式) 作者:Hical 阶段一:基础设施搭建 (域名与云端仓库) 1. 配置 DNS 域名解析 在域名控制台(如腾讯云 DNSPod)添加以下记录,将域名指向 GitHub 全球 CDN 节点: A 记录:主机记录 @,记录值分别填入(官方建议填2-4个做负载均衡): 185.199.108.153 185.199.109.153 CNAME 记录:主机记录 www,记录值填入你的 GitHub 默认分配域名(如 hical61.github.io)。 2. 创建空白 GitHub 仓库 登录 GitHub,新建一个 Public 仓库,命名为 你的用户名.github.io。 注意避坑:创建时务必保持完全空白,绝对不要勾选生成 README 或 .gitignore,以免与本地推送产生冲突。 阶段二:本地引擎组装 (Hugo 初始化) 1. 安装 Hugo 引擎(windows环境下) 去 GitHub Releases 下载带 extended 和 windows-amd64 的最新版 Hugo 压缩包。 解压出 hugo.exe,放入固定目录(如 D:\hugo\bin)。 将该路径加入 Windows 系统的 环境变量 PATH 中。 在终端执行 hugo version 验证安装成功。 2. 初始化博客目录与防掉线机制 在本地新建一个空文件夹作为博客源码库,打开 Git 终端执行: ...

March 25, 2026 · 3 min · 488 words

圆桌随机算法

前言 多年项目开发,总是会遇到很多随机算法场景,特别是策划要求进行权重累加且不放回抽取模式的场景。现总结一套圆桌随机算法以供参考。 第 1 版 —— 基础实现 第 1 版为最初版本,为了解决基本的项目需求而设计,实现了权重区间查找的核心逻辑。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 -- 圆桌随机类 g_tRoundTable = {} g_tRoundTable.__index = g_tRoundTable -- 构造函数 function g_tRoundTable:new() local instance = { items = {}, -- 保存随机项,形式: { {id=1, weight=10}, {id=2, weight=20} } totalWeight = 0, -- 权重总和 lastError = "" -- 保存最近的错误信息 } setmetatable(instance, self) return instance end -- 添加随机项 function g_tRoundTable:addItem(id, weight) if weight <= 0 then self.lastError = "Invalid weight: " .. tostring(weight) return false end table.insert(self.items, {id = id, weight = weight}) self.totalWeight = self.totalWeight + weight return true end -- 清空所有随机项 function g_tRoundTable:clearItems() self.items = {} self.totalWeight = 0 end -- 获取随机数(工具函数) function g_tRoundTable:getRandom(low, high) return math.random(low, high) -- 返回 [low, high] 间的随机数 end -- 查找随机数属于哪个区间 function g_tRoundTable:getZoneIndex(randomValue) for i, item in ipairs(self.items) do if randomValue < item.weight then return i else randomValue = randomValue - item.weight end end -- 理论上不会执行到这里 self.lastError = "Random value out of range" return 1 end -- 提取随机项 function g_tRoundTable:fetchItems(count, independent) local ntotalItems = #self.items if self.totalWeight <= 0 or ntotalItems == 0 then self.lastError = "No items to fetch from" return {} -- 空数组 end local results = {} for _ = 1, count do if self.totalWeight <= 0 or ntotalItems == 0 then break -- 如果池中没有可用项,跳出 end -- 生成随机数[0, totalWeight) local randomValue = self:getRandom(0, self.totalWeight - 1) local zoneIndex = self:getZoneIndex(randomValue) -- 添加结果 table.insert(results, self.items[zoneIndex].id) -- 如果是非独立模式,需要移除已取出的项 if not independent then self.totalWeight = self.totalWeight - self.items[zoneIndex].weight table.remove(self.items, zoneIndex) end end return results end -- 获取最近的错误 function g_tRoundTable:getLastError() return self.lastError end 第 2 版 —— 性能与功能升级 后来因需求越来越复杂,要求也越来越多,比如需要频繁动态调整、需要重复抽取,且性能也急需提升,故而 2.0 版本诞生了。 ...

March 24, 2026 · 25 min · 5123 words