<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>软角落-SoftNook</title><link>https://zelig.cn/</link><description>Good Luck To You!</description><item><title># 揭秘 Pascal TeeTree：构建高性能、类型安全的通用树形数据结构</title><link>https://zelig.cn/delphi/1383.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001143438tinhylgtdw.svg&quot; alt=&quot;# 揭秘 Pascal TeeTree：构建高性能、类型安全的通用树形数据结构&quot;&gt;&lt;/p&gt;&lt;p&gt;在软件开发中，树形结构（Tree Structure）无处不在。从文件系统的目录树、XML/JSON 的解析树，到编译器设计的抽象语法树（AST），以及 UI 框架中的组件层级。然而，在 Pascal/Delphi 环境中，开发者往往需要为每个具体场景手动定义一套节点类，导致大量重复代码且难以维护。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TeeTree&lt;/strong&gt; 是一个由 Steema 开发的开源 Pascal 库，旨在提供一种通用、灵活且类型安全的树形数据结构实现。它将“树的逻辑结构”与“存储的数据内容”解耦，让开发者能够快速构建复杂的层级模型而无需从零开始编写指针管理逻辑。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;核心设计理念&quot;&gt;核心设计理念&lt;/h2&gt;

&lt;p&gt;TeeTree 的核心在于&lt;strong&gt;泛型（Generics）&lt;/strong&gt;的深度应用。它不要求你继承某个特定的 &lt;code&gt;TTreeNode&lt;/code&gt; 类，而是允许你将任何自定义的类型（类或记录）作为节点的数据载体。&lt;/p&gt;

&lt;h3 id=&quot;1-解耦存储与结构&quot;&gt;1. 解耦存储与结构&lt;/h3&gt;

&lt;p&gt;在传统的树实现中，&lt;code&gt;Parent&lt;/code&gt; 和 &lt;code&gt;Children&lt;/code&gt; 属性通常直接定义在数据类中。这意味着你的业务对象必须依赖于树结构。TeeTree 采用了包装模式，将层级关系维护在内部容器中，你的业务对象保持纯净。&lt;/p&gt;

&lt;h3 id=&quot;2-类型安全&quot;&gt;2. 类型安全&lt;/h3&gt;

&lt;p&gt;通过 Pascal 的泛型支持，TeeTree 在编译时就能确保你存入和取出的是同一类型的数据，避免了频繁的类型转换（Type Casting）和潜在的运行时错误。&lt;/p&gt;

&lt;h3 id=&quot;3-高效的遍历机制&quot;&gt;3. 高效的遍历机制&lt;/h3&gt;

&lt;p&gt;TeeTree 提供了内置的迭代器和遍历算法，支持深度优先搜索（DFS）和广度优先搜索（BFS），极大简化了对复杂层级数据的处理逻辑。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;关键特性分析&quot;&gt;关键特性分析&lt;/h2&gt;

&lt;h3 id=&quot;灵活的节点管理&quot;&gt;灵活的节点管理&lt;/h3&gt;

&lt;p&gt;TeeTree 允许你轻松地执行以下操作：
- &lt;strong&gt;动态插入&lt;/strong&gt;：在任意节点下添加子节点。
- &lt;strong&gt;快速移动&lt;/strong&gt;：将整个子树从一个父节点迁移到另一个父节点。
- &lt;strong&gt;高效删除&lt;/strong&gt;：递归删除节点及其所有后代，并自动处理内存释放。&lt;/p&gt;

&lt;h3 id=&quot;强大的查询能力&quot;&gt;强大的查询能力&lt;/h3&gt;

&lt;p&gt;通过谓词（Predicate）函数，你可以快速在树中定位满足特定条件的节点。例如：“查找所有状态为‘激活’且层级深度大于 3 的节点”。&lt;/p&gt;

&lt;h3 id=&quot;低内存开销&quot;&gt;低内存开销&lt;/h3&gt;

&lt;p&gt;相比于重量级的 UI 控件（如 &lt;code&gt;TTreeView&lt;/code&gt;），TeeTree 是一个纯粹的数据结构库。它不依赖于任何图形界面库，因此非常适合用于后台服务、命令行工具或作为大型应用的底层数据模型。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;实践实例-构建一个简单的文件系统模拟器&quot;&gt;实践实例：构建一个简单的文件系统模拟器&lt;/h2&gt;

&lt;p&gt;为了更好地理解 TeeTree 的用法，我们来看一个实际的场景：模拟一个包含文件夹和文件的文件系统。&lt;/p&gt;

&lt;h3 id=&quot;场景定义&quot;&gt;场景定义&lt;/h3&gt;

&lt;p&gt;我们需要存储两种东西：文件夹（可以包含子项）和文件（叶子节点）。我们可以定义一个简单的 &lt;code&gt;TFileSystemItem&lt;/code&gt; 类。&lt;/p&gt;

&lt;h3 id=&quot;代码实现&quot;&gt;代码实现&lt;/h3&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;pascal&quot;&gt;pascal&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-pascal prism-line-numbers&quot; data-language=&quot;pascal&quot;&gt;program TeeTreeDemo;

{$APPLYMODE EXCEPTIONHANDLERS &amp;#39;ON&amp;#39;}

uses
  System.SysUtils,
  System.Generics.Collections,
  TeeTree; // 假设已安装 TeeTree 库

type
  // 定义我们要存储的数据对象
  TFileSystemItem = class
  public
    Name: string;
    IsFolder: Boolean;
    constructor Create(AName: string; AIsFolder: Boolean);
  end;

constructor TFileSystemItem.Create(AName: string; AIsFolder: Boolean);
begin
  Name := AName;
  IsFolder := AIsFolder;
end;

procedure PrintTree(Node: ITreeNode&amp;lt;TFileSystemItem&amp;gt;; Level: Integer = 0);
var
  Child: ITreeNode&amp;lt;TFileSystemItem&amp;gt;;
begin
  // 打印当前节点，根据层级添加缩进
  Writeln(StringOfChar(&amp;#39; &amp;#39;, Level * 2), (if Node.Data.IsFolder then &amp;#39;[Dir] &amp;#39; else &amp;#39;[File] &amp;#39;) + Node.Data.Name);
  
  // 递归遍历子节点
  for Child in Node.Children do
    PrintTree(Child, Level + 1);
end;

var
  FileTree: TTree&amp;lt;TFileSystemItem&amp;gt;;
  Root, Folder1, Folder2, File1, File2: ITreeNode&amp;lt;TFileSystemItem&amp;gt;;
begin
  try
    // 1. 初始化树
    FileTree := TTree&amp;lt;TFileSystemItem&amp;gt;.Create;

    // 2. 创建根节点 (Root)
    Root := FileTree.AddRoot(TFileSystemItem.Create(&amp;#39;C:\&amp;#39;, True));

    // 3. 创建文件夹并添加到根节点
    Folder1 := Root.AddChild(TFileSystemItem.Create(&amp;#39;Windows&amp;#39;, True));
    Folder2 := Root.AddChild(TFileSystemItem.Create(&amp;#39;Users&amp;#39;, True));

    // 4. 在 Windows 文件夹下添加文件
    Folder1.AddChild(TFileSystemItem.Create(&amp;#39;system32.dll&amp;#39;, False));
    Folder1.AddChild(TFileSystemItem.Create(&amp;#39;win.ini&amp;#39;, False));

    // 5. 在 Users 文件夹下创建子文件夹并添加文件
    var UserFolder := Folder2.AddChild(TFileSystemItem.Create(&amp;#39;Admin&amp;#39;, True));
    UserFolder.AddChild(TFileSystemItem.Create(&amp;#39;config.txt&amp;#39;, False));

    // 6. 遍历并输出结果
    Writeln(&amp;#39;File System Structure:&amp;#39;);
    PrintTree(FileTree.Root);

  finally
    FileTree.Free;
  end;
end.
&lt;/pre&gt;
&lt;h3 id=&quot;实例解析&quot;&gt;实例解析&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TTree&amp;lt;TFileSystemItem&amp;gt;&lt;/code&gt;&lt;/strong&gt;: 我们创建了一个泛型树，指定存储的数据类型为 &lt;code&gt;TFileSystemItem&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AddRoot&lt;/code&gt; 与 &lt;code&gt;AddChild&lt;/code&gt;&lt;/strong&gt;: TeeTree 提供了极其简洁的 API 来构建层级。你只需要传递数据对象，库会自动处理节点包装。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ITreeNode&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/strong&gt;: 每一个节点都被包装在一个接口中，这保证了你在操作树结构（如获取子节点）时，不会干扰到原始数据对象的属性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;递归遍历&lt;/strong&gt;: 通过 &lt;code&gt;Node.Children&lt;/code&gt; 迭代器，我们可以轻松实现深度优先遍历，将整个文件系统结构打印到控制台。&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;

&lt;h2 id=&quot;teetree-vs-传统-ttreeview&quot;&gt;TeeTree vs 传统 TTreeView&lt;/h2&gt;

&lt;p&gt;很多开发者会混淆 &lt;code&gt;TeeTree&lt;/code&gt; 与 Delphi 自带的 &lt;code&gt;TTreeView&lt;/code&gt;。下表对比了它们的本质区别：&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;特性&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;TTreeView (VCL/FMX)&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;TeeTree (Library)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;本质&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;UI 控件 (Visual Component)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;数据结构 (Data Structure)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;依赖&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;依赖图形界面库&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;纯 Pascal 代码，无依赖&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;数据存储&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;存储在 &lt;code&gt;TTreeNode&lt;/code&gt; 中，数据通常在 &lt;code&gt;Data&lt;/code&gt; 指针中 (untyped)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;泛型存储，类型安全 (&lt;code&gt;T&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;性能&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;受限于 UI 刷新，大数据量时卡顿&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;极高，仅内存操作&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;向用户展示树形界面&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;处理业务逻辑、解析数据、构建模型&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;灵活性&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;难以在非 UI 线程中使用&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;可在任何地方使用（包括服务端）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2 id=&quot;适用场景建议&quot;&gt;适用场景建议&lt;/h2&gt;

&lt;p&gt;如果你在开发以下类型的项目，TeeTree 将是你的绝佳选择：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;编译器/解释器开发&lt;/strong&gt;：构建抽象语法树（AST），需要频繁地对节点进行变换和分析。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂配置管理&lt;/strong&gt;：处理具有多级嵌套结构的配置文件（如自定义的 JSON-like 结构）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组织架构管理&lt;/strong&gt;：处理公司员工层级、权限继承树等业务逻辑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;游戏开发&lt;/strong&gt;：构建场景图（Scene Graph）或对话分支树。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高性能数据处理&lt;/strong&gt;：需要对大规模层级数据进行快速检索和过滤，且不需要立即显示在界面上。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;总结&quot;&gt;总结&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Steema/TeeTree&lt;/code&gt; 为 Pascal 社区提供了一个缺失已久的、工业级的通用树形结构实现。它通过泛型设计解决了类型安全问题，通过解耦设计解决了维护难题。无论你是需要一个简单的层级容器，还是一个复杂的逻辑树，TeeTree 都能让你从繁琐的指针管理中解脱出来，专注于核心业务逻辑的实现。&lt;/p&gt;
</description><pubDate>Tue, 13 Oct 2026 04:35:58 +0800</pubDate></item><item><title>C/C++-揭秘无线电监听：基于NRF24_Sniffer的2.4GHz数据抓包实战指南</title><link>https://zelig.cn/cpp/1382.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001211542qcytybscef.svg&quot; alt=&quot;C/C++-揭秘无线电监听：基于NRF24_Sniffer的2.4GHz数据抓包实战指南&quot;&gt;&lt;/p&gt;&lt;h1 id=&quot;深入解析-nrf24-sniffer-构建你的-2-4ghz-无线协议分析仪&quot;&gt;深入解析 NRF24_Sniffer：构建你的 2.4GHz 无线协议分析仪&lt;/h1&gt;

&lt;p&gt;在无线通信的开发过程中，最令人沮丧的事情莫过于“代码看起来没问题，但设备就是不通信”。当你无法在空中“看到”数据包时，调试就像在黑暗中摸索。&lt;strong&gt;NRF24_Sniffer&lt;/strong&gt; 正是为了解决这一痛点而生的开源项目。它将廉价的 nRF24L01+ 射频芯片转化为一个强大的协议分析仪，让你能够实时捕获、监听并分析 2.4GHz 频段的无线数据流。&lt;/p&gt;

&lt;h2 id=&quot;1-项目核心概述&quot;&gt;1. 项目核心概述&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;NRF24_Sniffer&lt;/code&gt; 是一个基于 C/C++ 开发的工具集，旨在将 nRF24L01+ 模块配置为“监听模式”（Promiscuous Mode）。&lt;/p&gt;

&lt;p&gt;通常情况下，nRF24L01+ 仅接收地址匹配的数据包。而该项目通过特定的寄存器配置和逻辑实现，使其能够忽略地址过滤，捕获空气中所有符合 nRF24 调制格式的数据包，并通过串口（UART）将原始字节流传输至 PC 端进行解析。&lt;/p&gt;

&lt;h3 id=&quot;核心技术栈&quot;&gt;核心技术栈&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;语言&lt;/strong&gt;：C/C++&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;硬件平台&lt;/strong&gt;：支持 Arduino、STM32 等主流 MCU&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;射频芯片&lt;/strong&gt;：nRF24L01+ / nRF24L01+ PA/LNA&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通信协议&lt;/strong&gt;：SPI (MCU &lt;span class=&quot;math inline&quot;&gt;\(\leftrightarrow\)&lt;/span&gt; nRF24) &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; UART (MCU &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; PC)&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2 id=&quot;2-硬件连接方案&quot;&gt;2. 硬件连接方案&lt;/h2&gt;

&lt;p&gt;要运行此项目，你需要准备一个基础的硬件链路。以下是典型的连接参考（以 Arduino Nano 为例）：&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;nRF24L01+ 引脚&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Arduino Nano 引脚&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;VCC&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;3.3V&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;严禁接 5V，否则芯片会烧毁&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;GND&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;GND&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;共地&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;CE&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;D9&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;片选/模式控制&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;CSN&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;D10&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;SPI 片选&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;SCK&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;D13&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;SPI 时钟&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;MOSI&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;D11&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;SPI 主出从入&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;MISO&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;D12&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;SPI 主入从出&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;专业建议&lt;/strong&gt;：由于 nRF24L01+ 在高速切换频率或高功率发射时对电流波动敏感，强烈建议在 VCC 和 GND 之间并联一个 &lt;span class=&quot;math inline&quot;&gt;\(10\mu\text{F}\)&lt;/span&gt; 到 &lt;span class=&quot;math inline&quot;&gt;\(100\mu\text{F}\)&lt;/span&gt; 的电解电容，以保证信号稳定。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;3-软件实现原理&quot;&gt;3. 软件实现原理&lt;/h2&gt;

&lt;h3 id=&quot;3-1-监听模式的实现&quot;&gt;3.1 监听模式的实现&lt;/h3&gt;

&lt;p&gt;NRF24_Sniffer 的核心在于对 &lt;code&gt;CONFIG&lt;/code&gt; 寄存器的操作。通过关闭自动应答（Auto-ACK）并配置接收模式，使其进入一个“宽口径”接收状态。&lt;/p&gt;

&lt;h3 id=&quot;3-2-频率扫描逻辑&quot;&gt;3.2 频率扫描逻辑&lt;/h3&gt;

&lt;p&gt;由于 nRF24L01+ 可以在 2.400GHz 到 2.525GHz 之间切换频率，该项目实现了快速跳频扫描机制。它可以：
- &lt;strong&gt;固定频道监听&lt;/strong&gt;：锁定在某个特定频率（如 2.402GHz）监听目标设备。
- &lt;strong&gt;全频段扫描&lt;/strong&gt;：快速轮询所有可用频道，检测哪个频道存在活跃的通信信号。&lt;/p&gt;

&lt;h3 id=&quot;3-3-数据流转路径&quot;&gt;3.3 数据流转路径&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;射频信号&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;nRF24L01+ (解调)&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;SPI 接口&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;MCU (封装)&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;UART 串口&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;PC 端分析软件&lt;/code&gt;。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;4-实战实例-捕获无线鼠标-传感器数据&quot;&gt;4. 实战实例：捕获无线鼠标/传感器数据&lt;/h2&gt;

&lt;p&gt;假设你有一个基于 nRF24L01+ 的无线温湿度传感器，你想分析它发送的数据格式。&lt;/p&gt;

&lt;h3 id=&quot;步骤-a-部署-sniffer-固件&quot;&gt;步骤 A：部署 Sniffer 固件&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;将 &lt;code&gt;NRF24_Sniffer&lt;/code&gt; 的源代码导入 IDE。&lt;/li&gt;
&lt;li&gt;在配置文件中设置目标频率（例如 &lt;code&gt;RF_CHANNEL = 76&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;烧录代码至 MCU。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;步骤-b-启动监听&quot;&gt;步骤 B：启动监听&lt;/h3&gt;

&lt;p&gt;打开串口监视器（波特率通常设为 115200），你会看到类似下面的原始数据流：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;[RX] CH: 76 | ADDR: 0xE7E7E7E7E7 | LEN: 8 | DATA: 0xAA 0x01 0x12 0x34 0x56 0x78 0x90 0xAB
[RX] CH: 76 | ADDR: 0xE7E7E7E7E7 | LEN: 8 | DATA: 0xAA 0x01 0x12 0x35 0x56 0x78 0x90 0xAC
&lt;/pre&gt;
&lt;h3 id=&quot;步骤-c-数据分析&quot;&gt;步骤 C：数据分析&lt;/h3&gt;

&lt;p&gt;通过观察上述数据，你可以进行逆向分析：
- &lt;strong&gt;固定头&lt;/strong&gt;：&lt;code&gt;0xAA 0x01&lt;/code&gt; 可能是数据包的同步头。
- &lt;strong&gt;变化位&lt;/strong&gt;：&lt;code&gt;0x34&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;0x35&lt;/code&gt; 可能是传感器数值的递增，或者是序列号（Sequence Number）。
- &lt;strong&gt;地址分析&lt;/strong&gt;：&lt;code&gt;0xE7E7E7E7E7&lt;/code&gt; 即为发送端的硬件地址。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;5-项目进阶-如何扩展功能&quot;&gt;5. 项目进阶：如何扩展功能？&lt;/h2&gt;

&lt;p&gt;如果你希望将这个项目提升到工业级水平，可以考虑以下扩展方向：&lt;/p&gt;

&lt;h3 id=&quot;5-1-结合-wireshark-进行可视化&quot;&gt;5.1 结合 Wireshark 进行可视化&lt;/h3&gt;

&lt;p&gt;目前项目输出的是文本流。你可以编写一个简单的 Python 脚本，将串口接收到的数据封装成 &lt;code&gt;pcap&lt;/code&gt; 格式的文件。这样你就可以直接使用 &lt;strong&gt;Wireshark&lt;/strong&gt; 这一顶级协议分析工具来过滤、搜索和分析无线包。&lt;/p&gt;

&lt;h3 id=&quot;5-2-实现-重放攻击-replay-attack-实验&quot;&gt;5.2 实现“重放攻击” (Replay Attack) 实验&lt;/h3&gt;

&lt;p&gt;在监听到特定指令（例如“开门”指令）后，将该数据包保存。随后将 nRF24L01+ 切换至发送模式，将原封不动的数据包再次发出。这在安全审计和协议漏洞测试中非常有用。&lt;/p&gt;

&lt;h3 id=&quot;5-3-频谱能量图&quot;&gt;5.3 频谱能量图&lt;/h3&gt;

&lt;p&gt;通过快速扫描所有频道并记录每个频道的 &lt;code&gt;RSSI&lt;/code&gt;（接收信号强度指示），你可以绘制出 2.4GHz 频段的能量分布图，从而避开 WiFi 干扰严重的频道。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;6-常见问题与注意事项-faq&quot;&gt;6. 常见问题与注意事项 (FAQ)&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: 为什么我捕获不到数据？&lt;/strong&gt;
- &lt;strong&gt;地址不匹配&lt;/strong&gt;：确保你关闭了地址过滤。
- &lt;strong&gt;频率偏移&lt;/strong&gt;：nRF24 的晶振存在偏差，如果发送端和接收端频率不完全一致，可能导致丢包。
- &lt;strong&gt;干扰过大&lt;/strong&gt;：2.4GHz 是极拥挤的频段，WiFi 信号可能会掩盖弱小的 nRF24 信号。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: 监听其他品牌的 2.4G 设备可以吗？&lt;/strong&gt;
- 只要对方使用的是 &lt;strong&gt;GFSK 调制&lt;/strong&gt; 且波特率与 nRF24 兼容（如 1Mbps 或 2Mbps），就有可能捕获到数据。但如果对方使用了私有跳频算法（FHSS），你将只能看到碎片化的数据包。&lt;/p&gt;

&lt;h2 id=&quot;7-总结&quot;&gt;7. 总结&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;NRF24_Sniffer&lt;/code&gt; 不仅仅是一个简单的代码库，它为开发者提供了一双“眼睛”，让不可见的无线电波变得可见。无论你是从事物联网产品开发，还是对无线电逆向工程感兴趣的爱好者，这个项目都是一个极佳的起点。通过它，你可以快速掌握无线协议分析的核心逻辑，并为构建更复杂的无线系统打下坚实基础。&lt;/p&gt;
</description><pubDate>Tue, 13 Oct 2026 02:30:58 +0800</pubDate></item><item><title>揭秘 Win31DB：用 Pascal 还原 Windows 3.1 数据库之美，让复古开发重获新生</title><link>https://zelig.cn/delphi/1381.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001143426dxsgmvojhw.svg&quot; alt=&quot;揭秘 Win31DB：用 Pascal 还原 Windows 3.1 数据库之美，让复古开发重获新生&quot;&gt;&lt;/p&gt;&lt;h1 id=&quot;win31db-一个致敬经典的-pascal-数据库项目&quot;&gt;Win31DB：一个致敬经典的 Pascal 数据库项目&lt;/h1&gt;

&lt;h2 id=&quot;1-项目概述&quot;&gt;1. 项目概述&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Win31DB&lt;/strong&gt; 是一个基于 Pascal 语言开发的轻量级数据库项目。从其命名和设计哲学来看，该项目旨在模拟或还原 Windows 3.1 时代的软件开发风格与数据库操作逻辑。在那个内存以 KB 计算、界面以灰白方块为主的年代，软件开发追求的是极致的精简与高效。&lt;/p&gt;

&lt;p&gt;Win31DB 不仅仅是一个简单的代码库，它更像是一次“数字考古”。它向现代开发者展示了在没有复杂 ORM 框架、没有云端分布式数据库的时代，开发者是如何通过底层的结构化存储和简单的 API 调用来管理数据的。&lt;/p&gt;

&lt;h2 id=&quot;2-核心设计理念&quot;&gt;2. 核心设计理念&lt;/h2&gt;

&lt;h3 id=&quot;2-1-极简主义-minimalism&quot;&gt;2.1 极简主义 (Minimalism)&lt;/h3&gt;

&lt;p&gt;Win31DB 摒弃了现代数据库冗余的配置项。它不依赖于庞大的服务端进程，而是倾向于文件驱动的存储方式，使得数据的迁移和读取变得极其简单。&lt;/p&gt;

&lt;h3 id=&quot;2-2-强类型约束&quot;&gt;2.2 强类型约束&lt;/h3&gt;

&lt;p&gt;得益于 Pascal 语言的特性，Win31DB 在数据定义阶段就引入了严格的类型检查。这确保了在读写二进制文件时，数据的偏移量和长度能够被精确控制，有效避免了内存溢出或数据损坏。&lt;/p&gt;

&lt;h3 id=&quot;2-3-兼容性与复古感&quot;&gt;2.3 兼容性与复古感&lt;/h3&gt;

&lt;p&gt;项目在接口设计上参考了早期的 Windows API 风格，通过简单的句柄（Handle）和结构体（Record）来操作数据集，为那些热爱复古计算（Retro Computing）的开发者提供了极佳的实践环境。&lt;/p&gt;

&lt;h2 id=&quot;3-技术实现分析&quot;&gt;3. 技术实现分析&lt;/h2&gt;

&lt;h3 id=&quot;3-1-存储机制&quot;&gt;3.1 存储机制&lt;/h3&gt;

&lt;p&gt;Win31DB 采用了典型的&lt;strong&gt;扁平文件存储 (Flat File Storage)&lt;/strong&gt;。数据在磁盘上以连续的记录块形式存储。
- &lt;strong&gt;定长记录&lt;/strong&gt;：每条记录占用相同的字节数，从而可以通过 &lt;code&gt;Offset = RecordIndex * RecordSize&lt;/code&gt; 快速定位到任意一条数据。
- &lt;strong&gt;索引映射&lt;/strong&gt;：为了提高查询速度，项目实现了简单的索引机制，将键值与文件指针建立映射关系。&lt;/p&gt;

&lt;h3 id=&quot;3-2-内存管理&quot;&gt;3.2 内存管理&lt;/h3&gt;

&lt;p&gt;在 Pascal 的实现中，项目大量使用了 &lt;code&gt;File&lt;/code&gt; 变量和 &lt;code&gt;Seek&lt;/code&gt; 指令。这种方式直接操作文件指针，最大限度地减少了内存占用，即使在处理较大规模的数据集时，也不会因为加载整个文件到内存而导致程序崩溃。&lt;/p&gt;

&lt;h2 id=&quot;4-快速上手实例&quot;&gt;4. 快速上手实例&lt;/h2&gt;

&lt;p&gt;为了让开发者快速理解 Win31DB 的工作流，以下是一个模拟的实现实例。假设我们要创建一个简单的“联系人管理系统”。&lt;/p&gt;

&lt;h3 id=&quot;4-1-定义数据结构&quot;&gt;4.1 定义数据结构&lt;/h3&gt;

&lt;p&gt;首先，我们需要定义一个记录类型，这决定了数据库中每一行数据的样子。&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;pascal&quot;&gt;pascal&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-pascal prism-line-numbers&quot; data-language=&quot;pascal&quot;&gt;type
  TContact = record
    ID: Integer;
    Name: array[0..29] of Char; // 固定长度的字符串
    Phone: array[0..19] of Char;
    Age: Integer;
  end;
&lt;/pre&gt;
&lt;h3 id=&quot;4-2-创建并写入数据&quot;&gt;4.2 创建并写入数据&lt;/h3&gt;

&lt;p&gt;使用 Win31DB 的核心逻辑，我们可以将数据持久化到磁盘。&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;pascal&quot;&gt;pascal&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-pascal prism-line-numbers&quot; data-language=&quot;pascal&quot;&gt;var
  DBFile: file of TContact;
  NewContact: TContact;
begin
  // 打开或创建数据库文件
  Assign(DBFile, &amp;#39;contacts.db&amp;#39;);
  Rewrite(DBFile);

  // 准备第一条数据
  NewContact.ID := 1;
  strcpy(NewContact.Name, &amp;#39;Zhang San&amp;#39;);
  strcpy(NewContact.Phone, &amp;#39;13800000000&amp;#39;);
  NewContact.Age := 25;
  
  // 写入文件
  Write(DBFile, NewContact);

  // 准备第二条数据
  NewContact.ID := 2;
  strcpy(NewContact.Name, &amp;#39;Li Si&amp;#39;);
  strcpy(NewContact.Phone, &amp;#39;13911111111&amp;#39;);
  NewContact.Age := 30;
  
  Write(DBFile, NewContact);

  Close(DBFile);
end;
&lt;/pre&gt;
&lt;h3 id=&quot;4-3-查询与检索&quot;&gt;4.3 查询与检索&lt;/h3&gt;

&lt;p&gt;通过 &lt;code&gt;Seek&lt;/code&gt; 操作，我们可以瞬间跳到指定记录。&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;pascal&quot;&gt;pascal&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-pascal prism-line-numbers&quot; data-language=&quot;pascal&quot;&gt;var
  DBFile: file of TContact;
  TargetContact: TContact;
begin
  Assign(DBFile, &amp;#39;contacts.db&amp;#39;);
  Reset(DBFile);

  // 假设我们要读取第 2 条记录 (索引从 0 开始)
  Seek(DBFile, 1); 
  Read(DBFile, TargetContact);

  WriteLn(&amp;#39;Name: &amp;#39;, TargetContact.Name);
  WriteLn(&amp;#39;Phone: &amp;#39;, TargetContact.Phone);

  Close(DBFile);
end;
&lt;/pre&gt;
&lt;h2 id=&quot;5-win31db-的适用场景&quot;&gt;5. Win31DB 的适用场景&lt;/h2&gt;

&lt;p&gt;虽然在商业生产环境中，我们更倾向于使用 PostgreSQL 或 MongoDB，但 Win31DB 在以下场景中具有独特价值：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;嵌入式小型工具&lt;/strong&gt;：开发不需要安装数据库服务、仅需存储少量配置或本地数据的轻量级工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复古软件开发&lt;/strong&gt;：为 Windows 3.1 模拟器或旧硬件编写应用程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算机科学教学&lt;/strong&gt;：作为学习“文件系统”、“记录偏移”和“二进制存储”的最佳教学案例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;极速原型开发&lt;/strong&gt;：在不需要复杂 SQL 语句的情况下，快速搭建一个本地数据存储原型。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;6-总结与展望&quot;&gt;6. 总结与展望&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;win31db&lt;/code&gt; 项目不仅仅是代码的堆砌，它是一种对软件工程纯粹时代的致敬。它告诉我们，在追求大数据的今天，简单的结构、明确的类型和直接的文件操作依然拥有其不可替代的效率和魅力。&lt;/p&gt;

&lt;p&gt;如果你是一名 Pascal 爱好者，或者对 90 年代的软件架构感兴趣，这个项目将为你打开一扇通往经典编程世界的大门。通过研究它的源码，你可以深刻理解数据是如何在物理磁盘上排布的，以及如何用最少的资源实现最核心的功能。&lt;/p&gt;
</description><pubDate>Mon, 12 Oct 2026 21:34:58 +0800</pubDate></item><item><title># 告别繁琐SQL：用 Pascal DBReader 实现极简数据库访问，让 Delphi/FreePascal 开发效率翻倍</title><link>https://zelig.cn/delphi/1380.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001143416qqupywpkge.png&quot; alt=&quot;# 告别繁琐SQL：用 Pascal DBReader 实现极简数据库访问，让 Delphi/FreePascal 开发效率翻倍&quot;&gt;&lt;/p&gt;&lt;p&gt;在传统的 Delphi 或 FreePascal 开发中，与数据库交互通常意味着编写冗长的 SQL 语句、手动管理数据集（DataSet）、处理复杂的参数绑定以及在代码中硬编码表名。这种方式不仅增加了代码量，还使得维护成本极高——一旦数据库表结构发生变化，开发者往往需要搜索并修改散落在项目各处的 SQL 字符串。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DBReader&lt;/strong&gt; 是一个旨在简化这一流程的轻量级 Pascal 库。它通过一种更接近“对象化”或“声明式”的方式，将数据库的读取操作抽象化，让开发者能够以更简洁的语法获取数据，从而将精力集中在业务逻辑而非底层的 SQL 拼接上。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;核心理念-从-写-sql-到-读数据&quot;&gt;核心理念：从“写 SQL”到“读数据”&lt;/h2&gt;

&lt;p&gt;DBReader 的核心目标是&lt;strong&gt;降低数据库访问的认知负载&lt;/strong&gt;。它并不试图取代强大的 SQL 语言，而是为常见的读取场景提供了一层优雅的封装。&lt;/p&gt;

&lt;p&gt;通过 DBReader，你可以将数据库查询视为一种“资源读取”过程。它通过预定义的配置或简单的 API 调用，将数据库记录直接映射到 Pascal 的数据结构中，极大地减少了样板代码（Boilerplate Code）的编写。&lt;/p&gt;

&lt;h3 id=&quot;dbreader-的主要优势&quot;&gt;DBReader 的主要优势&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;代码简洁度&lt;/strong&gt;：将数十行的 &lt;code&gt;TQuery&lt;/code&gt; 配置简化为几行函数调用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解耦&lt;/strong&gt;：通过抽象层，减少业务逻辑代码与具体 SQL 语句的强耦合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型安全&lt;/strong&gt;：利用 Pascal 的强类型特性，在读取数据时提供更&lt;/li&gt;
&lt;/ol&gt;
</description><pubDate>Mon, 12 Oct 2026 17:47:58 +0800</pubDate></item><item><title>Golang 极速上手指南：告别繁琐文档，用 cheat 打造你的专属命令行知识库</title><link>https://zelig.cn/golang/1379.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001202856hjbsynhrwz.svg&quot; alt=&quot;Golang 极速上手指南：告别繁琐文档，用 cheat 打造你的专属命令行知识库&quot;&gt;&lt;/p&gt;&lt;h1 id=&quot;告别-复制粘贴-用-cheat-打造你的-golang-命令行知识库&quot;&gt;告别“复制粘贴”：用 cheat 打造你的 Golang 命令行知识库&lt;/h1&gt;

&lt;p&gt;在开发 Golang 项目的过程中，我们经常会遇到这样的场景：记得某个 &lt;code&gt;go&lt;/code&gt; 命令可以实现某个功能，但具体参数怎么写？是 &lt;code&gt;go mod tidy&lt;/code&gt; 还是 &lt;code&gt;go mod clean&lt;/code&gt;？是 &lt;code&gt;go test -v&lt;/code&gt; 还是 &lt;code&gt;go test -run&lt;/code&gt;？&lt;/p&gt;

&lt;p&gt;大多数人的习惯是：打开浏览器 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 搜索 Google/StackOverflow &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 寻找官方文档 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 复制命令 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 回到终端粘贴。这个过程虽然不慢，但极其打断编程的“心流”状态。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cheat&lt;/strong&gt; 正是为了解决这个问题而生的工具。它不是一个简单的文档库，而是一个轻量级的、可自定义的命令行“速查表”（Cheat Sheet）管理器。&lt;/p&gt;

&lt;h2 id=&quot;什么是-cheat&quot;&gt;什么是 cheat？&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cheat&lt;/code&gt; 是一个用 Go 语言编写的开源工具，旨在为用户提供快速访问常用命令示例的方法。它通过简单的 &lt;code&gt;cheat &amp;lt;command&amp;gt;&lt;/code&gt; 指令，直接在终端输出该命令的常用用法示例，无需离开命令行界面。&lt;/p&gt;

&lt;p&gt;其核心理念是：&lt;strong&gt;与其阅读冗长的 Man Page（帮助手册），不如直接看几个能跑通的例子。&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;为什么-golang-开发者需要它&quot;&gt;为什么 Golang 开发者需要它？&lt;/h2&gt;

&lt;p&gt;Golang 的工具链（Toolchain）非常强大且统一，但随着版本迭代，命令组合越来越多。例如：
- &lt;strong&gt;模块管理&lt;/strong&gt;：&lt;code&gt;go mod&lt;/code&gt; 系列命令的细微差别。
- &lt;strong&gt;测试与基准&lt;/strong&gt;：&lt;code&gt;go test&lt;/code&gt; 的各种 flag（&lt;code&gt;-bench&lt;/code&gt;, &lt;code&gt;-cover&lt;/code&gt;, &lt;code&gt;-race&lt;/code&gt;）。
- &lt;strong&gt;构建优化&lt;/strong&gt;：&lt;code&gt;go build&lt;/code&gt; 的链接参数（&lt;code&gt;-ldflags&lt;/code&gt;）。
- &lt;strong&gt;代码分析&lt;/strong&gt;：&lt;code&gt;go vet&lt;/code&gt;, &lt;code&gt;go fmt&lt;/code&gt; 的高级用法。&lt;/p&gt;

&lt;p&gt;通过 &lt;code&gt;cheat&lt;/code&gt;，你可以将这些高频但难记的命令片段存储起来，实现秒级调用。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;快速安装与配置&quot;&gt;快速安装与配置&lt;/h2&gt;

&lt;h3 id=&quot;1-安装&quot;&gt;1. 安装&lt;/h3&gt;

&lt;p&gt;由于 &lt;code&gt;cheat&lt;/code&gt; 本身就是用 Go 写的，你可以直接通过 &lt;code&gt;go install&lt;/code&gt; 安装：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;go install github.com/cheat/cheat/cmd/cheat@latest
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;确保你的 &lt;code&gt;$GOPATH/bin&lt;/code&gt; 已添加到系统环境变量 &lt;code&gt;PATH&lt;/code&gt; 中。&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;2-初始化&quot;&gt;2. 初始化&lt;/h3&gt;

&lt;p&gt;安装完成后，你可以直接尝试查询一个内置的命令（如果已下载社区库）：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;cheat go
&lt;/pre&gt;
&lt;hr&gt;

&lt;h2 id=&quot;实战演练-为-golang-构建自定义速查表&quot;&gt;实战演练：为 Golang 构建自定义速查表&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cheat&lt;/code&gt; 最强大的地方在于支持自定义。你可以创建自己的 &lt;code&gt;.cheat&lt;/code&gt; 文件来记录你在项目中反复使用的复杂命令。&lt;/p&gt;

&lt;h3 id=&quot;第一步-创建自定义目录&quot;&gt;第一步：创建自定义目录&lt;/h3&gt;

&lt;p&gt;在你的家目录下创建 cheat 存储文件夹：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;mkdir -p ~/.config/cheat/cheats
&lt;/pre&gt;
&lt;h3 id=&quot;第二步-编写-golang-速查表&quot;&gt;第二步：编写 Golang 速查表&lt;/h3&gt;

&lt;p&gt;创建一个名为 &lt;code&gt;go.cheat&lt;/code&gt; 的文件：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;vim ~/.config/cheat/cheats/go.cheat
&lt;/pre&gt;
&lt;p&gt;在文件中输入以下内容（支持 Markdown 格式）：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;# Go 常用命令速查表

## 模块管理
- 整理依赖: `go mod tidy`
- 下载依赖: `go mod download`
- 验证依赖: `go mod verify`

## 测试与性能
- 运行所有测试: `go test ./...`
- 运行特定测试函数: `go test -v -run TestFunctionName`
- 运行基准测试: `go test -bench=. -benchmem`
- 检查竞态条件: `go test -race ./...`

## 构建与部署
- 编译为二进制文件: `go build -o app main.go`
- 交叉编译 (Linux): `CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app-linux`
- 注入版本号: `go build -ldflags &amp;#34;-X main.Version=1.0.0&amp;#34; -o app`

## 代码质量
- 格式化代码: `go fmt ./...`
- 静态检查: `go vet ./...`
&lt;/pre&gt;
&lt;h3 id=&quot;第三步-调用&quot;&gt;第三步：调用&lt;/h3&gt;

&lt;p&gt;现在，当你忘记如何运行基准测试时，只需输入：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;cheat go
&lt;/pre&gt;
&lt;p&gt;终端会立即呈现你刚才定义的清晰列表。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;进阶技巧-结合其他工具提升效率&quot;&gt;进阶技巧：结合其他工具提升效率&lt;/h2&gt;

&lt;h3 id=&quot;1-结合-fzf-进行模糊搜索&quot;&gt;1. 结合 &lt;code&gt;fzf&lt;/code&gt; 进行模糊搜索&lt;/h3&gt;

&lt;p&gt;如果你记录的命令非常多，可以使用 &lt;code&gt;fzf&lt;/code&gt; 来快速过滤：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;cheat go | fzf
&lt;/pre&gt;
&lt;h3 id=&quot;2-社区共享&quot;&gt;2. 社区共享&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;cheat&lt;/code&gt; 支持从远程仓库同步社区维护的速查表。你可以通过配置 &lt;code&gt;CHEATLEC&lt;/code&gt; 环境变量来加载社区的大规模知识库，这样你不仅能查 &lt;code&gt;go&lt;/code&gt;，还能查 &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;docker&lt;/code&gt;, &lt;code&gt;kubernetes&lt;/code&gt; 等所有开发工具。&lt;/p&gt;

&lt;h2 id=&quot;总结-从-记忆-转向-索引&quot;&gt;总结：从“记忆”转向“索引”&lt;/h2&gt;

&lt;p&gt;优秀的开发者不应该浪费脑力去记忆那些可以通过简单查询获得的语法细节，而应该将精力集中在架构设计和逻辑实现上。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cheat&lt;/code&gt; 将你的终端变成了一个可搜索的知识库。对于 Golang 开发者而言，它将 &lt;code&gt;go&lt;/code&gt; 工具链的复杂性降低到了极致——&lt;strong&gt;不再需要搜索，只需一个单词，答案就在眼前。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;项目地址：&lt;/strong&gt; &lt;a href=&quot;https://github.com/cheat/cheat&quot;&gt;https://github.com/cheat/cheat&lt;/a&gt;&lt;/p&gt;
</description><pubDate>Mon, 12 Oct 2026 14:42:58 +0800</pubDate></item><item><title>揭秘网络协议的“潜行者”：sniffjoke 深度解析与实战指南，让 C/C++ 开发者轻松掌握原始套接字抓包艺术</title><link>https://zelig.cn/cpp/1378.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001211517avnsccxvwv.svg&quot; alt=&quot;揭秘网络协议的“潜行者”：sniffjoke 深度解析与实战指南，让 C/C++ 开发者轻松掌握原始套接字抓包艺术&quot;&gt;&lt;/p&gt;&lt;h3 id=&quot;项目概述&quot;&gt;项目概述&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sniffjoke&lt;/code&gt; 是一个基于 C/C++ 编写的轻量级网络嗅探（Sniffing）示例项目。它并非一个商业级的防火墙或复杂的流量分析软件，而是一个极具教育意义的&lt;strong&gt;底层网络编程实践库&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;该项目的核心目标是向开发者展示如何利用 C 语言直接与操作系统内核交互，通过&lt;strong&gt;原始套接字（Raw Sockets）&lt;/strong&gt;截获经过网卡的网络数据包，并对其进行协议层级的解析。对于想要深入理解 TCP/IP 协议栈、学习网络安全分析或开发自定义协议分析器的开发者来说，&lt;code&gt;sniffjoke&lt;/code&gt; 提供了一个简洁且纯粹的起点。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;核心技术原理&quot;&gt;核心技术原理&lt;/h3&gt;

&lt;p&gt;要理解 &lt;code&gt;sniffjoke&lt;/code&gt; 的工作方式，首先需要理解其底层的技术支撑：&lt;/p&gt;

&lt;h4 id=&quot;1-原始套接字-raw-sockets&quot;&gt;1. 原始套接字 (Raw Sockets)&lt;/h4&gt;

&lt;p&gt;在常规的网络编程中，我们使用 &lt;code&gt;SOCK_STREAM&lt;/code&gt; (TCP) 或 &lt;code&gt;SOCK_DGRAM&lt;/code&gt; (UDP)，操作系统会自动处理 IP 头和 TCP/UDP 头。而 &lt;code&gt;sniffjoke&lt;/code&gt; 使用了 &lt;code&gt;SOCK_RAW&lt;/code&gt;。
这意味着程序可以绕过传输层，直接接收包含 &lt;strong&gt;IP 头部&lt;/strong&gt;在内的完整数据包。&lt;/p&gt;

&lt;h4 id=&quot;2-混杂模式-promiscuous-mode&quot;&gt;2. 混杂模式 (Promiscuous Mode)&lt;/h4&gt;

&lt;p&gt;通常，网卡会丢弃所有目标 MAC 地址不是本机的包。为了实现“嗅探”，&lt;code&gt;sniffjoke&lt;/code&gt; 引导用户或通过代码将网卡设置为“混杂模式”，使得网卡能够接收链路层上经过的所有流量，无论其目的地是谁。&lt;/p&gt;

&lt;h4 id=&quot;3-协议分层解析&quot;&gt;3. 协议分层解析&lt;/h4&gt;

&lt;p&gt;项目采用了典型的“剥洋葱”解析法：
- &lt;strong&gt;链路层 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 网络层&lt;/strong&gt;：解析以太网帧，提取 IP 报文。
- &lt;strong&gt;网络层 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 传输层&lt;/strong&gt;：解析 IP 头部，判断是 TCP、UDP 还是 ICMP。
- &lt;strong&gt;传输层 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 应用层&lt;/strong&gt;：解析端口号，提取实际的 Payload（有效载荷）。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;项目结构与关键代码逻辑&quot;&gt;项目结构与关键代码逻辑&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sniffjoke&lt;/code&gt; 的代码结构非常精简，主要逻辑集中在以下几个步骤：&lt;/p&gt;

&lt;h4 id=&quot;a-创建嗅探套接字&quot;&gt;A. 创建嗅探套接字&lt;/h4&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;// 简化逻辑示例
int sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 
&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;IPPROTO_TCP&lt;/code&gt;，程序告诉内核：“我想拦截所有 TCP 协议的流量”。&lt;/p&gt;

&lt;h4 id=&quot;b-定义协议结构体&quot;&gt;B. 定义协议结构体&lt;/h4&gt;

&lt;p&gt;为了解析二进制流，项目定义了与 RFC 标准一致的结构体。例如 IP 头部结构：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;struct ip_header {
    unsigned char  iph_ihl:4, iph_ver:4; // 版本和头长度
    unsigned char  iph_tos;              // 服务类型
    unsigned short iph_len;              // 总长度
    // ... 其他字段
};
&lt;/pre&gt;
&lt;p&gt;这种将二进制数据强制转换为结构体指针的操作，是 C 语言处理网络协议的高效之举。&lt;/p&gt;

&lt;h4 id=&quot;c-循环监听与打印&quot;&gt;C. 循环监听与打印&lt;/h4&gt;

&lt;p&gt;程序进入一个 &lt;code&gt;while(1)&lt;/code&gt; 循环，使用 &lt;code&gt;recvfrom()&lt;/code&gt; 阻塞等待数据包，一旦到达，立即解析并将其以人类可读的格式打印到终端。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;实战实例-如何运行与分析&quot;&gt;实战实例：如何运行与分析&lt;/h3&gt;

&lt;h4 id=&quot;1-环境准备&quot;&gt;1. 环境准备&lt;/h4&gt;

&lt;p&gt;由于原始套接字涉及底层网络权限，你不能以普通用户身份运行该程序。
- &lt;strong&gt;操作系统&lt;/strong&gt;：Linux (推荐)
- &lt;strong&gt;权限&lt;/strong&gt;：需要 &lt;code&gt;root&lt;/code&gt; 权限或 &lt;code&gt;CAP_NET_RAW&lt;/code&gt; 能力。&lt;/p&gt;

&lt;h4 id=&quot;2-编译与运行&quot;&gt;2. 编译与运行&lt;/h4&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;git clone https://github.com/vecna/sniffjoke
cd sniffjoke
make
sudo ./sniffjoke
&lt;/pre&gt;
&lt;h4 id=&quot;3-模拟抓包场景&quot;&gt;3. 模拟抓包场景&lt;/h4&gt;

&lt;p&gt;在运行 &lt;code&gt;sniffjoke&lt;/code&gt; 的同时，打开另一个终端，尝试访问一个 HTTP 网站或使用 &lt;code&gt;ping&lt;/code&gt; 命令：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;curl http://example.com
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;你在 &lt;code&gt;sniffjoke&lt;/code&gt; 终端中将看到类似以下的输出：&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;[TCP Packet] 
Source: 192.168.1.10:54321 -&amp;gt; Destination: 93.184.216.34:80
Flags: [SYN] Seq: 12345678 Win: 64240
Payload Length: 0
--------------------------------------------------
[TCP Packet] 
Source: 93.184.216.34:80 -&amp;gt; Destination: 192.168.1.10:54321
Flags: [SYN, ACK] Seq: 87654321 Ack: 12345679
Payload Length: 0
&lt;/pre&gt;
&lt;hr&gt;

&lt;h3 id=&quot;sniffjoke-的学习价值&quot;&gt;&lt;code&gt;sniffjoke&lt;/code&gt; 的学习价值&lt;/h3&gt;

&lt;p&gt;如果你是一名初学者，通过研究这个项目，你可以获得以下能力的提升：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;二进制数据处理能力&lt;/strong&gt;：学习如何使用指针偏移量和结构体对齐来解析字节流。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络协议实操&lt;/strong&gt;：不再仅仅在书本上阅读 TCP 三次握手，而是直接在屏幕上看到 &lt;code&gt;SYN&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;SYN-ACK&lt;/code&gt; &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; &lt;code&gt;ACK&lt;/code&gt; 的过程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统调用理解&lt;/strong&gt;：深入理解 &lt;code&gt;socket()&lt;/code&gt;, &lt;code&gt;bind()&lt;/code&gt;, &lt;code&gt;recvfrom()&lt;/code&gt; 等 Linux 系统调用在底层是如何运作的。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;进阶扩展建议&quot;&gt;进阶扩展建议&lt;/h3&gt;

&lt;p&gt;如果你想在 &lt;code&gt;sniffjoke&lt;/code&gt; 的基础上进行二次开发，可以尝试以下方向：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;增加协议支持&lt;/strong&gt;：目前项目可能侧重于 TCP，你可以尝试添加对 UDP 或 ICMP (Ping) 的解析。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实现简单的过滤机制&lt;/strong&gt;：增加一个参数，允许用户只抓取特定 IP 或特定端口的包（类似 &lt;code&gt;tcpdump&lt;/code&gt; 的 filter）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;导出为 PCAP 格式&lt;/strong&gt;：将抓到的包写入文件，使其可以用 Wireshark 打开分析。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检测异常流量&lt;/strong&gt;：编写简单的逻辑，如果短时间内收到大量 SYN 包，则在终端报警（实现一个极简的 SYN Flood 检测器）。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;总结&quot;&gt;总结&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sniffjoke&lt;/code&gt; 是一个典型的“小而美”的项目。它没有复杂的依赖，没有冗长的框架，只有最纯粹的 C 语言和最底层的网络协议。它是连接“理论网络知识”与“实际代码实现”之间的一座绝佳桥梁。&lt;/p&gt;
</description><pubDate>Mon, 12 Oct 2026 13:23:58 +0800</pubDate></item><item><title>在Delphi/Lazarus中实现高性能K-V存储：LevelDB-ObjectPascal 深度解析与实战指南</title><link>https://zelig.cn/delphi/1377.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001143404wmyxkgldnr.svg&quot; alt=&quot;在Delphi/Lazarus中实现高性能K-V存储：LevelDB-ObjectPascal 深度解析与实战指南&quot;&gt;&lt;/p&gt;&lt;h3 id=&quot;项目概述&quot;&gt;项目概述&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;LevelDB-ObjectPascal&lt;/strong&gt; 是一个为 Object Pascal (Delphi 和 Lazarus) 开发者量身定制的高性能键值存储（Key-Value Store）库。它通过对 Google 开发的 LevelDB C++ 库进行封装，将工业级的 LSM-Tree（Log-Structured Merge-Tree）存储引擎引入到 Pascal 生态中。&lt;/p&gt;

&lt;p&gt;在处理大规模数据存储、本地缓存、索引管理或需要快速随机读写且不希望部署完整关系型数据库（如 SQLite 或 PostgreSQL）的场景下，LevelDB-ObjectPascal 提供了一个轻量级且极速的替代方案。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;核心技术原理-为什么选择-leveldb&quot;&gt;核心技术原理：为什么选择 LevelDB？&lt;/h3&gt;

&lt;p&gt;传统的 B-Tree 数据库在面对海量写入时，由于随机 I/O 较高，性能会迅速下降。LevelDB 采用了 &lt;strong&gt;LSM-Tree&lt;/strong&gt; 架构，其核心逻辑是将所有的写入操作首先顺序写入日志（Write-Ahead Log），然后存储在内存中的有序表（MemTable）中。&lt;/p&gt;

&lt;p&gt;当内存表达到一定阈值时，它会被刷新到磁盘上的有序文件（SSTables）中。这种“将随机写转换为顺序写”的机制，使得 LevelDB 在写入吞吐量上具有压倒性优势。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LevelDB-ObjectPascal 的核心价值在于：&lt;/strong&gt;
1. &lt;strong&gt;零成本迁移&lt;/strong&gt;：无需编写复杂的 C++ 桥接代码，直接在 Pascal 中调用。
2. &lt;strong&gt;高性能&lt;/strong&gt;：继承了 LevelDB 的高效压缩和快速检索能力。
3. &lt;strong&gt;轻量化&lt;/strong&gt;：无需独立服务器进程，以库的形式集成在应用程序中。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;快速上手实例&quot;&gt;快速上手实例&lt;/h3&gt;

&lt;p&gt;为了让您快速理解如何使用该项目，以下是一个完整的集成示例。假设您已经通过项目地址克隆了代码并将其添加到您的 Delphi/Lazarus 搜索路径中。&lt;/p&gt;

&lt;h4 id=&quot;1-基础读写操作&quot;&gt;1. 基础读写操作&lt;/h4&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;pascal&quot;&gt;pascal&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-pascal prism-line-numbers&quot; data-language=&quot;pascal&quot;&gt;uses
  LevelDB; // 引入 LevelDB 单元

procedure LevelDB_BasicDemo;
var
  DB: TLevelDB;
  Value: string;
  Options: TDBOptions;
begin
  // 1. 配置数据库选项
  Options := TDBOptions.Create;
  try
    Options.CreateIfMissing := True; // 如果数据库文件夹不存在则创建
    
    // 2. 打开数据库 (指定存储路径)
    DB := TLevelDB.Open(&amp;#39;C:\MyData\LevelDB_Store&amp;#39;, Options);
    try
      // 3. 写入数据 (Put)
      // 注意：Key 和 Value 均采用字符串/字节流形式
      DB.Put(&amp;#39;user:1001&amp;#39;, &amp;#39;Zhang San&amp;#39;);
      DB.Put(&amp;#39;user:1002&amp;#39;, &amp;#39;Li Si&amp;#39;);
      DB.Put(&amp;#39;app_version&amp;#39;, &amp;#39;1.0.4&amp;#39;);

      // 4. 读取数据 (Get)
      if DB.Get(&amp;#39;user:1001&amp;#39;, Value) then
        Writeln(&amp;#39;Found User: &amp;#39;, Value)
      else
        Writeln(&amp;#39;User not found&amp;#39;);

      // 5. 删除数据 (Delete)
      DB.Delete(&amp;#39;user:1002&amp;#39;);

    finally
      DB.Free; // 必须释放，以确保数据库正确关闭并解锁文件
    end;
  finally
    Options.Free;
  end;
end;
&lt;/pre&gt;
&lt;h4 id=&quot;2-批量操作-writebatch&quot;&gt;2. 批量操作 (WriteBatch)&lt;/h4&gt;

&lt;p&gt;在处理大量数据导入时，单次 &lt;code&gt;Put&lt;/code&gt; 会产生多次磁盘同步，效率较低。使用 &lt;code&gt;WriteBatch&lt;/code&gt; 可以将多个操作原子化地一次性提交。&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;pascal&quot;&gt;pascal&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-pascal prism-line-numbers&quot; data-language=&quot;pascal&quot;&gt;procedure LevelDB_BatchDemo;
var
  DB: TLevelDB;
  Batch: TWriteBatch;
begin
  DB := TLevelDB.Open(&amp;#39;C:\MyData\LevelDB_Store&amp;#39;, nil);
  try
    Batch := TWriteBatch.Create;
    try
      // 将多个操作加入批处理队列
      Batch.Put(&amp;#39;sensor:1&amp;#39;, &amp;#39;23.5&amp;#39;);
      Batch.Put(&amp;#39;sensor:2&amp;#39;, &amp;#39;24.1&amp;#39;);
      Batch.Put(&amp;#39;sensor:3&amp;#39;, &amp;#39;22.8&amp;#39;);
      Batch.Delete(&amp;#39;old_sensor:1&amp;#39;);

      // 一次性提交到磁盘
      DB.Write(Batch);
    finally
      Batch.Free;
    end;
  finally
    DB.Free;
  end;
end;
&lt;/pre&gt;
&lt;h4 id=&quot;3-迭代器遍历-iterator&quot;&gt;3. 迭代器遍历 (Iterator)&lt;/h4&gt;

&lt;p&gt;LevelDB 的 Key 是有序存储的，这使得范围查询（Range Scan）变得非常高效。&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;pascal&quot;&gt;pascal&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-pascal prism-line-numbers&quot; data-language=&quot;pascal&quot;&gt;procedure LevelDB_IteratorDemo;
var
  DB: TLevelDB;
  Iter: TLevelDBIterator;
begin
  DB := TLevelDB.Open(&amp;#39;C:\MyData\LevelDB_Store&amp;#39;, nil);
  try
    Iter := DB.GetIterator;
    try
      // 移动到第一个元素
      Iter.SeekToFirst;
      
      // 遍历所有键值对
      while Iter.Valid do
      begin
        Writeln(Format(&amp;#39;Key: %s | Value: %s&amp;#39;, [Iter.Key, Iter.Value]));
        Iter.Next; // 移动到下一个
      end;
    finally
      Iter.Free;
    end;
  finally
    DB.Free;
  end;
end;
&lt;/pre&gt;
&lt;hr&gt;

&lt;h3 id=&quot;进阶使用场景建议&quot;&gt;进阶使用场景建议&lt;/h3&gt;

&lt;h4 id=&quot;场景-a-本地配置与状态持久化&quot;&gt;场景 A：本地配置与状态持久化&lt;/h4&gt;

&lt;p&gt;对于复杂的桌面软件，使用 &lt;code&gt;.ini&lt;/code&gt; 或 &lt;code&gt;.json&lt;/code&gt; 文件在数据量大时加载缓慢。可以使用 LevelDB 存储用户偏好设置，通过 &lt;code&gt;Key = &#039;setting.theme&#039;&lt;/code&gt;, &lt;code&gt;Value = &#039;dark&#039;&lt;/code&gt; 快速读写。&lt;/p&gt;

&lt;h4 id=&quot;场景-b-大规模索引缓存&quot;&gt;场景 B：大规模索引缓存&lt;/h4&gt;

&lt;p&gt;如果您有一个包含数百万条记录的文本文件，可以通过 LevelDB 构建一个索引：&lt;code&gt;Key = &#039;line_offset:12345&#039;&lt;/code&gt;, &lt;code&gt;Value = &#039;keyword_A&#039;&lt;/code&gt;。这样在搜索关键词时，无需全盘扫描，直接通过 LevelDB 定位文件偏移量。&lt;/p&gt;

&lt;h4 id=&quot;场景-c-消息队列本地缓冲&quot;&gt;场景 C：消息队列本地缓冲&lt;/h4&gt;

&lt;p&gt;在网络不稳定的环境下，可以将待发送的消息先写入 LevelDB。由于其顺序写特性，即使在低端硬件上也能保证极高的写入速度，待网络恢复后再通过迭代器依次读取并发送。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;开发注意事项-避坑指南&quot;&gt;开发注意事项（避坑指南）&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;单进程锁定&lt;/strong&gt;：LevelDB 采用文件锁机制。&lt;strong&gt;同一个数据库文件夹在同一时间只能被一个进程打开&lt;/strong&gt;。如果您在 IDE 中运行程序时没有关闭之前的实例，再次运行会抛出 &lt;code&gt;Lock&lt;/code&gt; 错误。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存管理&lt;/strong&gt;：由于该项目是对 C++ 库的封装，请务必严格遵守 &lt;code&gt;try...finally&lt;/code&gt; 结构，确保 &lt;code&gt;TLevelDB&lt;/code&gt; 和 &lt;code&gt;TLevelDBIterator&lt;/code&gt; 被正确 &lt;code&gt;Free&lt;/code&gt;，否则会导致内存泄漏或文件句柄占用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key 的设计&lt;/strong&gt;：LevelDB 是按 Key 的字节顺序排序的。如果您需要进行范围查询，建议 Key 采用固定长度或前缀形式（例如 &lt;code&gt;user:0001&lt;/code&gt;, &lt;code&gt;user:0002&lt;/code&gt;），以便于使用 &lt;code&gt;Seek&lt;/code&gt; 定位。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能调优&lt;/strong&gt;：在 &lt;code&gt;TDBOptions&lt;/code&gt; 中，可以通过调整 &lt;code&gt;WriteBufferSize&lt;/code&gt;（写入缓冲区大小）来平衡内存占用与写入性能。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;总结&quot;&gt;总结&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;LevelDB-ObjectPascal&lt;/code&gt; 为 Pascal 开发者提供了一个强大的底层存储原语。它摒弃了传统 SQL 数据库的繁琐模式定义，以极简的 API 实现了极高的吞吐量。无论您是在开发高性能的桌面应用，还是在构建复杂的本地数据处理工具，这个项目都将是您工具箱中不可或缺的利器。&lt;/p&gt;
</description><pubDate>Mon, 12 Oct 2026 12:43:58 +0800</pubDate></item><item><title>Pascal-# 突破内存限制：用 DuckDB_OPCL 实现海量数据的极速分析与内存映射</title><link>https://zelig.cn/delphi/1376.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001143352pwpjpimwnh.svg&quot; alt=&quot;Pascal-# 突破内存限制：用 DuckDB_OPCL 实现海量数据的极速分析与内存映射&quot;&gt;&lt;/p&gt;&lt;p&gt;在现代数据分析领域，我们经常面临一个尴尬的困境：数据集太大，内存装不下（导致 OOM）；但如果使用传统的磁盘数据库，查询速度又慢得令人发指。DuckDB 凭借其列式存储和向量化执行引擎，已经成为了分析型查询（OLAP）的宠儿。然而，当数据量达到 TB 级别且需要频繁随机访问或部分加载时，如何更高效地管理内存映射（Memory-mapped files）成为了性能优化的关键。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DuckDB_OPCL&lt;/strong&gt; 正是为了解决这一痛点而生的项目。它通过引入 &lt;strong&gt;OPCL (Optimized Page Cache Layer)&lt;/strong&gt; 机制，为 DuckDB 提供了更灵活、更高效的内存映射管理能力，使得在资源受限的环境下处理超大规模数据集成为可能。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;1-什么是-duckdb-opcl&quot;&gt;1. 什么是 DuckDB_OPCL？&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;DuckDB_OPCL&lt;/code&gt; 是一个针对 DuckDB 的扩展/增强实现，其核心目标是优化 &lt;strong&gt;Page Cache（页缓存）&lt;/strong&gt; 的行为。&lt;/p&gt;

&lt;p&gt;在标准的数据库架构中，数据从磁盘加载到内存通常经过一个复杂的缓存层。如果缓存策略不当，会导致频繁的 Page Fault（页缺失），从而引发严重的 I/O 瓶颈。&lt;code&gt;DuckDB_OPCL&lt;/code&gt; 通过优化页面的加载、替换策略以及与操作系统的内存映射（mmap）交互方式，实现了以下目标：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;降低内存足迹&lt;/strong&gt;：不再需要将整个数据集加载到 RAM 中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提升随机访问速度&lt;/strong&gt;：通过优化页缓存层，减少磁盘寻道时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;增强稳定性&lt;/strong&gt;：有效防止在处理超大文件时因内存溢出而导致的进程崩溃。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-核心技术原理&quot;&gt;2. 核心技术原理&lt;/h2&gt;

&lt;h3 id=&quot;2-1-内存映射-mmap-的增强&quot;&gt;2.1 内存映射 (mmap) 的增强&lt;/h3&gt;

&lt;p&gt;传统的 &lt;code&gt;mmap&lt;/code&gt; 将文件直接映射到虚拟地址空间，由操作系统内核决定何时换入/换出页面。但在高并发的分析查询中，内核的通用策略往往不是最优的。&lt;code&gt;DuckDB_OPCL&lt;/code&gt; 介入了这一过程，通过更精细的控制，确保热点数据尽可能留在内存中，而冷数据被快速释放。&lt;/p&gt;

&lt;h3 id=&quot;2-2-优化页缓存层-opcl&quot;&gt;2.2 优化页缓存层 (OPCL)&lt;/h3&gt;

&lt;p&gt;OPCL 引入了一套针对列式存储特性的缓存算法。由于 DuckDB 是列式存储，查询通常只涉及少数几列。OPCL 能够识别这种访问模式，优先缓存被频繁扫描的列片段，从而在物理内存有限的情况下，模拟出拥有巨大内存的查询性能。&lt;/p&gt;

&lt;h3 id=&quot;2-3-向量化执行的协同&quot;&gt;2.3 向量化执行的协同&lt;/h3&gt;

&lt;p&gt;DuckDB 的核心竞争力在于向量化执行（Vectorized Execution）。&lt;code&gt;DuckDB_OPCL&lt;/code&gt; 在底层确保了数据页的对齐和预取，使得向量化引擎在处理数据块时，能够以最快速度从缓存中获取连续的内存地址，最大化 CPU L1/L2 缓存的命中率。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;3-适用场景&quot;&gt;3. 适用场景&lt;/h2&gt;

&lt;p&gt;如果你遇到以下情况，&lt;code&gt;DuckDB_OPCL&lt;/code&gt; 将是你的理想选择：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据集 &amp;gt; 物理内存&lt;/strong&gt;：例如你只有 32GB 内存，但需要分析一个 500GB 的 Parquet 或 DuckDB 原生文件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低延迟随机查询&lt;/strong&gt;：需要对海量数据进行频繁的点查询或小范围聚合，而不想每次都全表扫描。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;边缘计算/资源受限环境&lt;/strong&gt;：在笔记本电脑或小型云服务器上运行大规模分析任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;替代传统重量级数据库&lt;/strong&gt;：希望获得类似 ClickHouse 的性能，但又不想要复杂的集群部署，倾向于单机文件存储。&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;

&lt;h2 id=&quot;4-快速上手与实例演示&quot;&gt;4. 快速上手与实例演示&lt;/h2&gt;

&lt;p&gt;由于 &lt;code&gt;DuckDB_OPCL&lt;/code&gt; 是一个底层增强项目，其使用方式通常集成在 DuckDB 的存储引擎调用中。以下是一个模拟的逻辑流程，展示如何利用该项目处理海量数据。&lt;/p&gt;

&lt;h3 id=&quot;4-1-环境准备&quot;&gt;4.1 环境准备&lt;/h3&gt;

&lt;p&gt;首先，你需要克隆项目并根据文档进行编译（通常需要 C++ 编译环境）：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;git clone https://github.com/Libaud/DuckDB_OPCL.git
cd DuckDB_OPCL
# 按照 README 进行编译安装
mkdir build &amp;amp;&amp;amp; cd build
cmake ..
make -j$(nproc)
&lt;/pre&gt;
&lt;h3 id=&quot;4-2-实例场景-分析-1tb-的日志文件&quot;&gt;4.2 实例场景：分析 1TB 的日志文件&lt;/h3&gt;

&lt;p&gt;假设你有一个巨大的 &lt;code&gt;.duckdb&lt;/code&gt; 数据库文件，包含数亿行用户行为日志。&lt;/p&gt;

&lt;h4 id=&quot;传统方式-可能-oom&quot;&gt;传统方式（可能 OOM）：&lt;/h4&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;-- 如果内存不足，执行此操作可能会导致系统卡死或崩溃
SELECT user_id, COUNT(*) 
FROM large_logs 
GROUP BY user_id;
&lt;/pre&gt;
&lt;h4 id=&quot;使用-duckdb-opcl-增强后的方式&quot;&gt;使用 DuckDB_OPCL 增强后的方式：&lt;/h4&gt;

&lt;p&gt;通过 OPCL 优化后的存储引擎，你可以配置内存限制，让系统自动通过内存映射管理数据：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;-- 设置内存限制，强制触发 OPCL 的高效页缓存管理
SET memory_limit = &amp;#39;8GB&amp;#39;; 
PRAGMA threads = 8;

-- 执行聚合查询
-- 此时 OPCL 会在后台高效地将需要的列页映射到内存，并快速回收不再使用的页
SELECT user_id, COUNT(*) 
FROM large_logs 
GROUP BY user_id;
&lt;/pre&gt;
&lt;h3 id=&quot;4-3-性能对比预期&quot;&gt;4.3 性能对比预期&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;指标&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;标准 DuckDB (内存不足时)&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;DuckDB + OPCL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;内存占用&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;易触发 OOM 或剧烈 Swap&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;稳定在设定的 &lt;code&gt;memory_limit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;首次扫描速度&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;受限于磁盘 I/O&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;接近磁盘顺序读极限&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;重复查询速度&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;依赖 OS Page Cache (不可控)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;极快 (由 OPCL 精确控制热点页)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;启动时间&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;较快&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;极快 (mmap 瞬时映射)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2 id=&quot;5-总结与展望&quot;&gt;5. 总结与展望&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;DuckDB_OPCL&lt;/code&gt; 不仅仅是一个简单的补丁，它代表了一种&lt;strong&gt;“以空间换时间，以智能管理替代暴力加载”&lt;/strong&gt;的存储哲学。它将 DuckDB 的分析能力从“内存数据库”推向了真正的“超大规模单机分析引擎”。&lt;/p&gt;

&lt;p&gt;对于数据工程师而言，这意味着你可以在不需要部署复杂的分布式集群（如 Spark 或 Presto）的情况下，在单机上处理 TB 级的数据。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;项目核心价值点回顾：&lt;/strong&gt;
- &lt;strong&gt;极简部署&lt;/strong&gt;：保持了 DuckDB 无需安装、单文件存储的特性。
- &lt;strong&gt;极致性能&lt;/strong&gt;：通过优化 Page Cache 消除 I/O 瓶颈。
- &lt;strong&gt;内存友好&lt;/strong&gt;：让 16GB 内存也能跑 1TB 的数据分析。&lt;/p&gt;

&lt;p&gt;如果你正在寻找一种方式来压榨单机硬件的最后一点性能，或者深受内存溢出之苦，那么 &lt;code&gt;DuckDB_OPCL&lt;/code&gt; 绝对值得尝试。&lt;/p&gt;
</description><pubDate>Mon, 12 Oct 2026 05:52:58 +0800</pubDate></item><item><title>Golang-用 Go 语言构建高性能推送系统：Gorose 深度解析与实战指南，助你轻松实现百万级设备消息触达</title><link>https://zelig.cn/golang/1375.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001202850zzwusmgwir.svg&quot; alt=&quot;Golang-用 Go 语言构建高性能推送系统：Gorose 深度解析与实战指南，助你轻松实现百万级设备消息触达&quot;&gt;&lt;/p&gt;&lt;h1 id=&quot;gorose-企业级-golang-推送平台解决方案&quot;&gt;Gorose：企业级 Golang 推送平台解决方案&lt;/h1&gt;

&lt;p&gt;在现代互联网应用中，推送通知（Push Notification）是提升用户留存率和活跃度的核心手段。然而，面对不同平台的推送协议（如苹果 APNs、谷歌 FCM、小米、华为、OPPO、vivo 等），开发者往往需要面对碎片化的 API 接口、复杂的鉴权机制以及极高的并发压力。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gorose&lt;/strong&gt; 是一个基于 Golang 开发的开源推送平台，旨在为开发者提供一个统一的推送接口，屏蔽底层各平台的差异，实现“一次编写，全平台触达”。&lt;/p&gt;

&lt;h2 id=&quot;1-为什么选择-gorose&quot;&gt;1. 为什么选择 Gorose？&lt;/h2&gt;

&lt;p&gt;在没有 Gorose 之前，如果你想给全平台用户发通知，你的代码逻辑可能是这样的：
- 如果是 iOS &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 调用 APNs 接口 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 处理证书 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 处理 Token。
- 如果是 Android 华为 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 调用华为推送 API &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 处理 AppID &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 处理 Secret。
- 如果是 Android 小米 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 调用小米推送 API &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 处理 AppKey &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 处理 Secret。&lt;/p&gt;

&lt;p&gt;这种方式导致代码冗余且难以维护。&lt;strong&gt;Gorose 通过抽象层将这些复杂的逻辑封装起来&lt;/strong&gt;，你只需要调用 Gorose 的统一 API，由它来决定将消息路由到哪个平台。&lt;/p&gt;

&lt;h3 id=&quot;核心优势&quot;&gt;核心优势&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;统一接口&lt;/strong&gt;：一套 API 覆盖主流移动端推送平台。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高并发性能&lt;/strong&gt;：得益于 Golang 的 goroutine 机制，Gorose 能够高效处理海量推送请求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解耦架构&lt;/strong&gt;：将推送业务逻辑与具体平台实现分离，方便扩展新平台。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;灵活配置&lt;/strong&gt;：支持通过配置文件或数据库动态管理各平台的凭据。&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2 id=&quot;2-核心架构设计&quot;&gt;2. 核心架构设计&lt;/h2&gt;

&lt;p&gt;Gorose 的设计遵循了典型的“适配器模式”。其核心流程如下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;API 层&lt;/strong&gt;：接收客户端的推送请求（包含目标用户 ID、消息内容、平台类型等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;路由层&lt;/strong&gt;：根据请求中的平台标识，将任务分发给对应的推送驱动（Driver）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;驱动层（Driver）&lt;/strong&gt;：针对不同平台（如 &lt;code&gt;apns&lt;/code&gt;, &lt;code&gt;fcm&lt;/code&gt;, &lt;code&gt;huawei&lt;/code&gt;）实现具体的协议封装，负责与第三方推送服务器通信。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;发送层&lt;/strong&gt;：通过 HTTP/2 或 TCP 长连接将消息发送至目标平台。&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;

&lt;h2 id=&quot;3-快速上手实例&quot;&gt;3. 快速上手实例&lt;/h2&gt;

&lt;p&gt;为了让你快速理解 Gorose 的工作方式，下面通过一个模拟场景展示如何使用该项目。&lt;/p&gt;

&lt;h3 id=&quot;3-1-环境准备&quot;&gt;3.1 环境准备&lt;/h3&gt;

&lt;p&gt;首先，克隆项目并安装依赖：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;git clone https://github.com/gohouse/gorose.git
cd gorose
go mod tidy
&lt;/pre&gt;
&lt;h3 id=&quot;3-2-基础配置&quot;&gt;3.2 基础配置&lt;/h3&gt;

&lt;p&gt;在启动 Gorose 之前，你需要在配置文件（通常是 &lt;code&gt;config.yaml&lt;/code&gt; 或环境变量）中配置各平台的密钥。例如：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;push:
  apns:
    certificate_path: &amp;#34;./certs/apns.p12&amp;#34;
    password: &amp;#34;your_password&amp;#34;
    team_id: &amp;#34;TEAM123456&amp;#34;
  fcm:
    api_key: &amp;#34;your_fcm_server_key&amp;#34;
  huawei:
    app_id: &amp;#34;10000000&amp;#34;
    app_secret: &amp;#34;your_secret&amp;#34;
&lt;/pre&gt;
&lt;h3 id=&quot;3-3-代码实现实例&quot;&gt;3.3 代码实现实例&lt;/h3&gt;

&lt;p&gt;假设你现在要开发一个简单的推送服务，调用 Gorose 的能力向一个 iOS 用户和一个华为用户发送通知。&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;package main

import (
	&amp;#34;fmt&amp;#34;
	&amp;#34;log&amp;#34;

	&amp;#34;github.com/gohouse/gorose/push&amp;#34;
)

func main() {
	// 1. 初始化推送管理器
	// 在实际项目中，manager 通常是单例，在程序启动时加载配置完成初始化
	manager, err := push.NewManager() 
	if err != nil {
		log.Fatalf(&amp;#34;初始化失败: %v&amp;#34;, err)
	}

	// 2. 构建推送消息
	// 统一的消息结构，无需关心底层平台差异
	msg := &amp;amp;push.Message{
		Title:   &amp;#34;限时特惠！&amp;#34;,
		Content: &amp;#34;您关注的商品已降价，快来看看吧！&amp;#34;,
		Payload: map[string]string{
			&amp;#34;product_id&amp;#34;: &amp;#34;12345&amp;#34;,
			&amp;#34;category&amp;#34;:   &amp;#34;electronics&amp;#34;,
		},
	}

	// 3. 定义目标设备
	// 这里的 Target 包含了平台类型和设备 Token
	targets := []push.Target{
		{
			Platform: &amp;#34;apns&amp;#34;,   // 苹果设备
			Token:    &amp;#34;ios_device_token_abc123&amp;#34;,
		},
		{
			Platform: &amp;#34;huawei&amp;#34;,  // 华为设备
			Token:    &amp;#34;huawei_device_token_xyz789&amp;#34;,
		},
	}

	// 4. 执行异步推送
	// Gorose 内部会根据 Platform 自动选择对应的 Driver
	results := manager.Send(msg, targets)

	// 5. 处理发送结果
	for _, res := range results {
		if res.Error != nil {
			fmt.Printf(&amp;#34;发送失败 [%s]: %v\n&amp;#34;, res.Platform, res.Error)
		} else {
			fmt.Printf(&amp;#34;发送成功 [%s]: MessageID = %s\n&amp;#34;, res.Platform, res.MessageID)
		}
	}
}
&lt;/pre&gt;
&lt;hr&gt;

&lt;h2 id=&quot;4-进阶应用场景&quot;&gt;4. 进阶应用场景&lt;/h2&gt;

&lt;h3 id=&quot;4-1-批量推送与分片&quot;&gt;4.1 批量推送与分片&lt;/h3&gt;

&lt;p&gt;在面对百万级用户推送时，直接调用 API 会导致内存溢出或被第三方平台限流。建议结合 Gorose 与消息队列（如 Kafka 或 RabbitMQ）：
- &lt;strong&gt;生产者&lt;/strong&gt;：将推送任务写入 Kafka。
- &lt;strong&gt;消费者&lt;/strong&gt;：启动多个 Gorose 消费者实例，从 Kafka 消费任务并分批调用 &lt;code&gt;manager.Send&lt;/code&gt;。
- &lt;strong&gt;限流控制&lt;/strong&gt;：在消费者端实现令牌桶算法，确保发送速率符合平台要求。&lt;/p&gt;

&lt;h3 id=&quot;4-2-动态-token-管理&quot;&gt;4.2 动态 Token 管理&lt;/h3&gt;

&lt;p&gt;在实际业务中，设备 Token 是动态变化的。建议构建一个 &lt;code&gt;TokenStore&lt;/code&gt; 数据库：
- 用户登录 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 客户端上传 Token &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 存储至 MySQL/Redis（关联 UserID）。
- 发送通知 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 根据 UserID 查询所有关联的 Token &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 构造 &lt;code&gt;push.Target&lt;/code&gt; 列表 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 调用 Gorose。&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&quot;5-性能优化建议&quot;&gt;5. 性能优化建议&lt;/h2&gt;

&lt;p&gt;为了最大化 Gorose 的性能，建议在部署时关注以下几点：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;连接复用&lt;/strong&gt;：确保底层 HTTP 客户端启用了 Keep-Alive，避免频繁建立 TCP 连接带来的开销。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发控制&lt;/strong&gt;：虽然 Go 的 goroutine 很轻量，但面对极大规模推送时，应使用 &lt;code&gt;Worker Pool&lt;/code&gt;（工作池）模式，防止瞬间创建过多 goroutine 导致 OOM。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误重试机制&lt;/strong&gt;：针对网络抖动导致的发送失败，可以实现一个简单的指数退避重试逻辑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控指标&lt;/strong&gt;：接入 Prometheus，监控每个平台的发送成功率、延迟以及 API 响应时间。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;6-总结&quot;&gt;6. 总结&lt;/h2&gt;

&lt;p&gt;Gorose 为 Golang 开发者提供了一个极其简洁的推送抽象层。它将复杂的第三方 API 细节隐藏在背后，让开发者能够专注于业务逻辑而非协议实现。无论你是构建一个小型的通知系统，还是支撑一个千万级用户的社交平台，Gorose 都能提供坚实的基础支撑。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;项目资源回顾：&lt;/strong&gt;
- GitHub 地址：&lt;code&gt;https://github.com/gohouse/gorose&lt;/code&gt;
- 核心能力：统一接口 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 多平台驱动 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; 高并发发送。&lt;/p&gt;
</description><pubDate>Mon, 12 Oct 2026 02:46:58 +0800</pubDate></item><item><title>C/C++-揭秘 LTE 空口流量抓包：srsLTE-Sniffer 深度解析与实战指南</title><link>https://zelig.cn/cpp/1374.html</link><description>&lt;p&gt;&lt;img src=&quot;/zb_users/upload/2026/10/20261001211455coogifiran.svg&quot; alt=&quot;C/C++-揭秘 LTE 空口流量抓包：srsLTE-Sniffer 深度解析与实战指南&quot;&gt;&lt;/p&gt;&lt;h3 id=&quot;项目概述&quot;&gt;项目概述&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;srsLTE-Sniffer&lt;/strong&gt; 是一个基于 C/C++ 开发的轻量级 LTE 协议分析工具，旨在为 LTE 网络研究人员、安全分析师和通信工程师提供一种高效的方式来捕获和分析 LTE 空口（Air Interface）的信令流量。&lt;/p&gt;

&lt;p&gt;在现代移动通信研究中，直接从物理层获取解调后的协议数据（PDU）具有极高的挑战性。srsLTE-Sniffer 通过与 &lt;code&gt;srsRAN&lt;/code&gt; 等开源 LTE 软件定义无线电（SDR）框架集成，能够将复杂的物理层信号转化为可读的协议报文，并支持将其导出为标准格式（如 PCAP），以便使用 Wireshark 等专业工具进行深度协议分析。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;核心功能特性&quot;&gt;核心功能特性&lt;/h3&gt;

&lt;h4 id=&quot;1-实时流量截获&quot;&gt;1. 实时流量截获&lt;/h4&gt;

&lt;p&gt;项目能够实时监听指定的 LTE 逻辑信道，捕获下行（DL）和上行（UL）的控制面（Control Plane）与用户面（User Plane）数据。&lt;/p&gt;

&lt;h4 id=&quot;2-协议栈解封装&quot;&gt;2. 协议栈解封装&lt;/h4&gt;

&lt;p&gt;srsLTE-Sniffer 不仅仅是简单的二进制抓包，它实现了对 LTE 协议栈关键层级的解封装，包括：
*   &lt;strong&gt;MAC 层&lt;/strong&gt;：分析调度信息和混合自动重传请求（HARQ）。
*   &lt;strong&gt;RLC 层&lt;/strong&gt;：处理分段与重组。
*   &lt;strong&gt;PDCP 层&lt;/strong&gt;：处理头部压缩（ROHC）与加密/解密（在配置密钥的情况下）。&lt;/p&gt;

&lt;h4 id=&quot;3-pcap-标准输出&quot;&gt;3. PCAP 标准输出&lt;/h4&gt;

&lt;p&gt;支持将捕获到的数据流实时写入 &lt;code&gt;.pcap&lt;/code&gt; 文件。这意味着用户无需编写复杂的解析脚本，直接将文件拖入 Wireshark，即可利用其强大的 LTE 协议解析插件查看信令流程（如 Attach, Tracking Area Update 等）。&lt;/p&gt;

&lt;h4 id=&quot;4-低延迟-c-实现&quot;&gt;4. 低延迟 C++ 实现&lt;/h4&gt;

&lt;p&gt;采用高性能 C++ 编写，确保在处理高吞吐量的 LTE 流量时，不会因为处理能力不足而导致丢包，保证了抓包的完整性。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;技术架构分析&quot;&gt;技术架构分析&lt;/h3&gt;

&lt;p&gt;srsLTE-Sniffer 的工作流程可以概括为：&lt;strong&gt;SDR 硬件 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; srsRAN 物理层 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; srsLTE-Sniffer 拦截层 &lt;span class=&quot;math inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; PCAP 文件&lt;/strong&gt;。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;接口层&lt;/strong&gt;：它通过挂载到 srsRAN 的内部接口，在数据从物理层传递到上层协议栈的交界处进行“镜像”拷贝。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;过滤机制&lt;/strong&gt;：允许用户根据 UE（用户设备）的 IMSI 或 TMSI 进行过滤，避免在多用户环境下被海量无关数据淹没。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存管理&lt;/strong&gt;：使用环形缓冲区（Ring Buffer）机制，确保数据采集与磁盘写入异步进行，最大限度降低对实时通信性能的影响。&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h3 id=&quot;快速上手实例&quot;&gt;快速上手实例&lt;/h3&gt;

&lt;h4 id=&quot;1-环境准备&quot;&gt;1. 环境准备&lt;/h4&gt;

&lt;p&gt;在使用 srsLTE-Sniffer 之前，你需要确保系统中已经安装了：
*   &lt;strong&gt;srsRAN&lt;/strong&gt;：作为基础的 LTE 软件栈。
*   &lt;strong&gt;SDR 设备&lt;/strong&gt;：如 USRP B210 或 BladeRF。
*   &lt;strong&gt;编译工具&lt;/strong&gt;：&lt;code&gt;cmake&lt;/code&gt;, &lt;code&gt;g++&lt;/code&gt;, &lt;code&gt;make&lt;/code&gt;。&lt;/p&gt;

&lt;h4 id=&quot;2-编译安装&quot;&gt;2. 编译安装&lt;/h4&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;# 克隆仓库
git clone https://github.com/Wooniety/srsLTE-Sniffer.git
cd srsLTE-Sniffer

# 创建构建目录
mkdir build &amp;amp;&amp;amp; cd build
cmake ..
make
&lt;/pre&gt;
&lt;h4 id=&quot;3-运行实例&quot;&gt;3. 运行实例&lt;/h4&gt;

&lt;p&gt;假设你已经启动了一个 srsENB（基站），现在想要抓取该基站下所有 UE 的流量：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;# 运行 sniffer，指定输出文件为 capture.pcap
sudo ./srsLTE-Sniffer -f capture.pcap -i eth0
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;进阶用法：针对特定 UE 抓包&lt;/strong&gt;
如果你只想分析某个特定设备的信令流程，可以通过参数指定过滤条件（具体参数参考项目 &lt;code&gt;README&lt;/code&gt;）：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;sudo ./srsLTE-Sniffer -f ue_specific.pcap --imsi 123456789012345
&lt;/pre&gt;
&lt;h4 id=&quot;4-分析结果&quot;&gt;4. 分析结果&lt;/h4&gt;

&lt;p&gt;运行一段时间后，停止程序，然后使用 Wireshark 打开文件：&lt;/p&gt;
&lt;div class=&quot;prism-show-language&quot;&gt;&lt;div class=&quot;prism-show-language-label&quot; data-language=&quot;text&quot;&gt;text&lt;/div&gt;&lt;/div&gt;&lt;pre class=&quot;prism-highlight prism- language-text prism-line-numbers&quot; data-language=&quot;text&quot;&gt;wireshark capture.pcap
&lt;/pre&gt;
&lt;p&gt;在 Wireshark 中，你可以通过过滤器 &lt;code&gt;lte-rrc&lt;/code&gt; 或 &lt;code&gt;lte-nas&lt;/code&gt; 快速定位到：
*   &lt;strong&gt;RRC Connection Setup&lt;/strong&gt;：查看设备如何建立连接。
*   &lt;strong&gt;NAS Attach Request&lt;/strong&gt;：分析设备如何向核心网请求入网。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;应用场景&quot;&gt;应用场景&lt;/h3&gt;

&lt;h4 id=&quot;场景-a-协议开发与调试&quot;&gt;场景 A：协议开发与调试&lt;/h4&gt;

&lt;p&gt;当你开发自定义的 LTE 核心网或基站功能时，srsLTE-Sniffer 可以作为“逻辑示波器”，帮你确认发送的信令是否符合 3GPP 标准，以及接收端是否正确响应。&lt;/p&gt;

&lt;h4 id=&quot;场景-b-网络安全审计&quot;&gt;场景 B：网络安全审计&lt;/h4&gt;

&lt;p&gt;通过分析空口流量，安全研究员可以检测是否存在异常的信令攻击（如伪基站攻击、拒绝服务攻击），或者分析特定设备的通信模式。&lt;/p&gt;

&lt;h4 id=&quot;场景-c-学术研究&quot;&gt;场景 C：学术研究&lt;/h4&gt;

&lt;p&gt;对于学习 LTE 协议栈的学生，通过实际抓取并分析 &lt;code&gt;Attach&lt;/code&gt; 流程的 PCAP 包，比阅读数百页的 3GPP 规范文档要直观得多。&lt;/p&gt;

&lt;hr&gt;

&lt;h3 id=&quot;总结与建议&quot;&gt;总结与建议&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;srsLTE-Sniffer&lt;/code&gt; 为开源 LTE 社区提供了一个缺失的环节——&lt;strong&gt;可见性&lt;/strong&gt;。它将复杂的无线电波转化为结构化的数据包，极大地降低了 LTE 协议分析的门槛。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;建议：&lt;/strong&gt;
*   &lt;strong&gt;性能优化&lt;/strong&gt;：在高速率传输时，建议将 PCAP 文件写入高速 SSD，以防止 I/O 瓶颈。
*   &lt;strong&gt;配合使用&lt;/strong&gt;：建议将本项目与 &lt;code&gt;srsRAN_4G&lt;/code&gt; 结合使用，构建一个完整的“基站-终端-分析仪”实验环境。
*   &lt;strong&gt;法律合规&lt;/strong&gt;：请务必在屏蔽室或合法授权的频段内进行测试，避免干扰公共移动网络。&lt;/p&gt;
</description><pubDate>Mon, 12 Oct 2026 01:20:58 +0800</pubDate></item></channel></rss>