<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Keunlas</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://keunlas.net/</id>
  <link href="https://keunlas.net/" rel="alternate"/>
  <link href="https://keunlas.net/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Keunlas</rights>
  <subtitle>路漫漫其修远兮</subtitle>
  <title>面向未知</title>
  <updated>2026-03-28T13:24:45.665Z</updated>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <category term="开发" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/"/>
    <category term="通用知识" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/%E9%80%9A%E7%94%A8%E7%9F%A5%E8%AF%86/"/>
    <category term="regex" scheme="https://keunlas.net/tags/regex/"/>
    <content>
      <![CDATA[<blockquote><p>基于 ECMAScript 正则表达式语法</p></blockquote><p>一对括号就是一对分组，废话不多说，直接看例子。</p><h1 id="分组引用"><a href="# 分组引用" class="headerlink" title="分组引用"></a>分组引用 </h1><p> 对 <code>aabacaabaa</code> 匹配 <code>(a+)b\1</code>，可以匹配到的地方有两处 <code>aba</code> 和 <code>aabaa</code>。</p><p>其中 <code>\1</code> 指第一个分组所匹配到的东西。匹配过程如下。</p><ul><li>从位置 0 开始，<code>(a+)</code> 贪婪匹配 <code>aa</code>（位置 0-1），然后匹配 <code>b</code>（位置 2）成功，但 <code>\1</code> 需要匹配 <code>aa</code>，而位置 3-4 是 <code>ac</code>，匹配失败。</li><li>回溯后，<code>(a+)</code> 匹配 <code>a</code>（位置 0），然后匹配 <code>b</code>，但位置 1 是 <code>a</code>，匹配失败。</li><li>从位置 1 开始，<code>(a+)</code> 匹配 <code>a</code>（位置 1），然后匹配 <code>b</code>（位置 2）成功，<code>\1</code> 需要匹配 <code>a</code>，位置 3 是 <code>a</code>，匹配成功。</li><li>第一次匹配完成，匹配结果为 <code>aba</code>（位置 1-3），分组 1 捕获 <code>a</code>。</li><li>从位置 4 开始，字符 <code>c</code> 不符合 <code>a+</code>，跳过。</li><li>从位置 5 开始，<code>(a+)</code> 匹配 <code>aa</code>（位置 5-6），然后匹配 <code>b</code>（位置 7）成功，<code>\1</code> 需要匹配 <code>aa</code>，位置 8-9 是 <code>aa</code>，匹配成功。</li><li>第二次匹配完成，匹配结果为 <code>aabaa</code>（位置 5-9），分组 1 捕获 <code>aa</code>。</li></ul><p>如果一个正则有多个分组 <code>\2</code> <code>\3</code> 等同理。</p>]]>
    </content>
    <id>https://keunlas.net/posts/7357b855/</id>
    <link href="https://keunlas.net/posts/7357b855/"/>
    <published>2026-03-11T05:21:33.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>基于 ECMAScript 正则表达式语法</p>
</blockquote>
<p>一对括号就是一对分组，废话不多说，直接看例子。</p>
<h1 id="分组引用"><a href="# 分组引用" class="headerlink" tit]]>
    </summary>
    <title>正则分组子表达式</title>
    <updated>2026-03-28T13:24:45.665Z</updated>
  </entry>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <category term="开发" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/"/>
    <category term="通用知识" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/%E9%80%9A%E7%94%A8%E7%9F%A5%E8%AF%86/"/>
    <category term="regex" scheme="https://keunlas.net/tags/regex/"/>
    <content>
      <![CDATA[<blockquote><p> 基于 ECMAScript 正则表达式语法 </p></blockquote><p> 断言匹配条件不消耗输入中的任何字符，可参考 <code>^</code> <code>$</code>，只断言是文本开头或者结尾，不消耗任何字符。</p><h1 id="零宽度正向先行断言"><a href="# 零宽度正向先行断言" class="headerlink" title="零宽度正向先行断言"></a> 零宽度正向先行断言 </h1><blockquote><p><code>(?=...)</code> 当 … 能在当前位置匹配输入，则匹配。</p></blockquote><p> 例如对 <code>baaba</code> 匹配 <code>(?=(a+))a*b</code>，匹配过程如下。</p><ul><li> 从位置 0 开始，字符 <code>b</code> 不符合 <code>a+</code>，前瞻匹配失败，移动到下一位置。</li><li> 从位置 1 开始，<code>a+</code> 贪婪匹配 <code>aa</code>（位置 1-2），前瞻匹配成功，不消耗字符，当前位置仍在位置 1。</li><li> 从位置 1 继续匹配 <code>a*b</code>，<code>a*</code> 贪婪匹配 <code>aa</code>（位置 1-2），然后 <code>b</code> 匹配位置 3 的 <code>b</code> 成功。</li><li> 最终匹配结果为 <code>aaba</code>（位置 1-3），分组 1 捕获 <code>aa</code>。</li></ul><p> 再来看一个例子，对 <code>abc2ABC</code> 匹配 <code>(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).&#123;6,&#125;</code>。这个正则是匹配包含大写字母、小写字母和数字，且长度至少为 6 的字符串。</p><p> 首先看第一个前瞻匹配 <code>(?=.*[a-z])</code>，用来判断是否包含小写英文字母。</p><ul><li> 从位置 0 开始，<code>.*</code> 贪婪匹配 <code>abc2ABC</code> 这七个字符，导致 <code>[a-z]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc2AB</code> 这六个字符，剩下 <code>C</code>，<code>[a-z]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc2A</code> 这五个字符，剩下 <code>B</code>，<code>[a-z]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc2</code> 这四个字符，剩下 <code>A</code>，<code>[a-z]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc</code> 这三个字符，剩下 <code>2</code>，<code>[a-z]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>ab</code> 这两个字符，剩下 <code>c</code>，<code>[a-z]</code> 匹配 <code>c</code> 成功。</li><li> 第一个前瞻匹配成功，当前位置仍在位置 0。</li></ul><p> 第二个前瞻匹配 <code>(?=.*[A-Z])</code>，用来判断是否包含大写英文字母。</p><ul><li> 从位置 0 开始，<code>.*</code> 贪婪匹配 <code>abc2ABC</code> 这七个字符，导致 <code>[A-Z]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc2AB</code> 这六个字符，剩下 <code>C</code>，<code>[A-Z]</code> 匹配 <code>C</code> 成功。</li><li> 第二个前瞻匹配成功，当前位置仍在位置 0。</li></ul><p> 第三个前瞻匹配 <code>(?=.*[0-9])</code>，用来判断是否包含数字。</p><ul><li> 从位置 0 开始，<code>.*</code> 贪婪匹配 <code>abc2ABC</code> 这七个字符，导致 <code>[0-9]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc2AB</code> 这六个字符，剩下 <code>C</code>，<code>[0-9]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc2A</code> 这五个字符，剩下 <code>B</code>，<code>[0-9]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc2</code> 这四个字符，剩下 <code>A</code>，<code>[0-9]</code> 匹配失败。</li><li><code>.*</code> 回溯后匹配 <code>abc</code> 这三个字符，剩下 <code>2</code>，<code>[0-9]</code> 匹配 <code>2</code> 成功。</li><li> 第三个前瞻匹配成功，当前位置仍在位置 0。</li></ul><p> 最后 <code>.&#123;6,&#125;</code> 从位置 0 匹配 <code>abc2ABC</code> 这七个字符，匹配完成。</p><p> 最终匹配结果为 <code>abc2ABC</code>，满足包含大写字母、小写字母和数字，且长度至少为 6 的条件。</p><h1 id="零宽度负向先行断言"><a href="# 零宽度负向先行断言" class="headerlink" title="零宽度负向先行断言"></a> 零宽度负向先行断言 </h1><blockquote><p><code>(?!...)</code> 当 … 不能在当前位置匹配输入，则匹配。</p></blockquote><p> 零宽度负向先行断言和正向的相反，类比零宽度正向先行断言即可。</p>]]>
    </content>
    <id>https://keunlas.net/posts/92f1340d/</id>
    <link href="https://keunlas.net/posts/92f1340d/"/>
    <published>2026-03-11T04:31:16.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p> 基于 ECMAScript 正则表达式语法 </p>
</blockquote>
<p> 断言匹配条件不消耗输入中的任何字符，可参考 <code>^</code> <code>$</code>，只断言是文本开头或者结尾，不消耗任何字符。</p>]]>
    </summary>
    <title>正则前瞻匹配（零宽度先行断言）</title>
    <updated>2026-03-28T13:24:45.665Z</updated>
  </entry>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <category term="开发" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/"/>
    <category term="SQLite3" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/SQLite3/"/>
    <category term="sqlite" scheme="https://keunlas.net/tags/sqlite/"/>
    <category term="sqlite3" scheme="https://keunlas.net/tags/sqlite3/"/>
    <content>
      <![CDATA[<h1 id="线程安全问题"><a href="# 线程安全问题" class="headerlink" title="线程安全问题"></a>线程安全问题</h1><p>SQLite3 在编译的时候可以通过添加定义来控制整个库的线程安全问题。</p><p>当 <code>SQLITE_THREADSAFE</code> 这个宏为 <code>0</code> 时，整个库是线程不安全的。</p><p>当 <code>SQLITE_THREADSAFE</code> 这个宏为 <code>1</code> 时，整个库是线程安全的。</p><p>当 <code>SQLITE_THREADSAFE</code> 这个宏为 <code>2</code> 时，整个库是线程安全的，但是同一个 <code>sqlite3* db</code> 不能被多个线程同时使用。</p><p>当编译的时候 <code>SQLITE_THREADSAFE</code> 为 <code>1</code> 或者 <code>2</code> 时，可以通过 <code>sqlite3_config()</code> 这个接口来更改线程安全模式：</p><ul><li><code>SQLITE_CONFIG_SINGLETHREAD</code> 单线程</li><li><code>SQLITE_CONFIG_MULTITHREAD</code> 多线程</li><li><code>SQLITE_CONFIG_SERIALIZED</code> 串行化</li></ul><h1 id="面向对象类"><a href="# 面向对象类" class="headerlink" title="面向对象类"></a>面向对象类</h1><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string_view&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unordered_map&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SQLite3</span> &#123;</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  <span class="keyword">using</span> TableRow = std::unordered_map&lt;std::string, std::string&gt;;</span><br><span class="line">  <span class="keyword">using</span> ExecCallback = std::function&lt;<span class="built_in">bool</span>(TableRow)&gt;;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  <span class="built_in">SQLite3</span>(<span class="type">const</span> std::string_view&amp; db_name);</span><br><span class="line">  ~<span class="built_in">SQLite3</span>();</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="type">int</span> <span class="title">close</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="type">void</span> <span class="title">exec</span><span class="params">(<span class="type">const</span> std::string_view&amp; sql)</span></span>;</span><br><span class="line">  <span class="function"><span class="type">void</span> <span class="title">exec</span><span class="params">(<span class="type">const</span> std::string_view&amp; sql, ExecCallback callback)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">  std::string db_name_;</span><br><span class="line">  sqlite3* db_&#123;<span class="literal">nullptr</span>&#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>我设置了两个成员变量，一个是数据库连接，另一个是打开的数据库名称。</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">std::string db_name_;</span><br><span class="line">sqlite3* db_&#123;<span class="literal">nullptr</span>&#125;;</span><br></pre></td></tr></table></figure><h1 id="数据库的开启"><a href="# 数据库的开启" class="headerlink" title="数据库的开启"></a>数据库的开启 </h1><p> 首先是类的构造函数，主要是打开数据库连接，并在出错时抛出异常信息。</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">SQLite3::<span class="built_in">SQLite3</span>(<span class="type">const</span> std::string_view&amp; db_name) : <span class="built_in">db_name_</span>(db_name) &#123;</span><br><span class="line">  <span class="keyword">auto</span> errcode = <span class="built_in">sqlite3_open</span>(db_name.<span class="built_in">data</span>(), &amp;db_);</span><br><span class="line">  <span class="keyword">if</span> (errcode != SQLITE_OK) &#123;</span><br><span class="line">    <span class="comment">// 抛出或处理异常信息</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="数据库的关闭"><a href="# 数据库的关闭" class="headerlink" title="数据库的关闭"></a>数据库的关闭 </h1><p> 然后是析构和关闭数据库连接。</p><p>析构函数因为不能抛出异常，所以我使用了 <code>sqlite3_close_v2</code> 来关闭连接。</p><p>主动 close 则是使用 <code>sqlite3_close</code> 接口，并返回错误代码。</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">SQLite3::~<span class="built_in">SQLite3</span>() &#123;</span><br><span class="line">  <span class="keyword">if</span> (db_) &#123;</span><br><span class="line">    <span class="built_in">sqlite3_close_v2</span>(db_);</span><br><span class="line">    db_ = <span class="literal">nullptr</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">SQLite3::close</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="keyword">auto</span> errcode = <span class="built_in">sqlite3_close</span>(db_);</span><br><span class="line">  <span class="keyword">if</span> (errcode == SQLITE_OK) &#123;</span><br><span class="line">    db_ = <span class="literal">nullptr</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> errcode;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="执行 -SQL- 语句"><a href="# 执行 -SQL- 语句" class="headerlink" title="执行 SQL 语句"></a>执行 SQL 语句 </h1><h2 id="无回调函数"><a href="# 无回调函数" class="headerlink" title="无回调函数"></a> 无回调函数 </h2><p> 无回调函数的操作，只需要执行 SQL 语句，并抛出或者处理执行失败的情况即可。</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">SQLite3::exec</span><span class="params">(<span class="type">const</span> std::string_view&amp; sql)</span> </span>&#123;</span><br><span class="line">  <span class="type">char</span>* errstr = <span class="literal">nullptr</span>;</span><br><span class="line">  <span class="type">int</span> errcode = <span class="built_in">sqlite3_exec</span>(db_, sql.<span class="built_in">data</span>(), <span class="literal">nullptr</span>, <span class="literal">nullptr</span>, &amp;errstr);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (errcode != SQLITE_OK) &#123;</span><br><span class="line">    std::string msg = errstr ? errstr : <span class="string">&quot;Unknown error&quot;</span>;</span><br><span class="line">    <span class="built_in">sqlite3_free</span>(errstr);</span><br><span class="line">    <span class="keyword">throw</span> std::<span class="built_in">runtime_error</span>(</span><br><span class="line">        std::format(<span class="string">&quot;Failed to execute SQL: &#123;&#125;\nError SQL: &#123;&#125;&quot;</span>, msg, sql));</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="有回调函数"><a href="# 有回调函数" class="headerlink" title="有回调函数"></a>有回调函数 </h2><p> 当执行一些带有结果的 SQL 语句时，就需要回调函数去处理结果。</p><p>我定义了两个类型用来封装 <code>sqlite3_exec</code> 中的回调函数。</p><p><code>ExecCallback</code> 对象的返回值为 bool 类型，用来指示回调函数是否成功执行。</p><p>并且 <code>ExecCallback</code> 对象拥有一个参数 <code>TableRow</code>，这是一个哈希表，存储该行的每一个列数据的 name 和 value 的键值对。</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> TableRow = std::unordered_map&lt;std::string, std::string&gt;;</span><br><span class="line"><span class="keyword">using</span> ExecCallback = std::function&lt;<span class="built_in">bool</span>(TableRow)&gt;;</span><br></pre></td></tr></table></figure><p>我通过 <code>void* context</code> 传递 <code>ExecCallback</code> 对象。</p><p>当回调函数触发时，填充 <code>TableRow row</code> 对象的数据，并以此为参数调用 <code>ExecCallback</code> 对象。</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">SQLite3::exec</span><span class="params">(<span class="type">const</span> std::string_view&amp; sql, ExecCallback callback)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">auto</span> c_callback = [](<span class="type">void</span>* context, <span class="type">int</span> col_size, <span class="type">char</span>** col_values,</span><br><span class="line">                       <span class="type">char</span>** col_names) -&gt; <span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">auto</span>* cb = <span class="built_in">static_cast</span>&lt;ExecCallback*&gt;(context);</span><br><span class="line">    TableRow row;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; col_size; i++) &#123;</span><br><span class="line">      std::string col_name = col_names[i];</span><br><span class="line">      std::string value = col_values[i] ? col_values[i] : <span class="string">&quot;&quot;</span>;</span><br><span class="line">      row[col_name] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">bool</span> success = (*cb)(row);</span><br><span class="line">    <span class="keyword">return</span> success ? <span class="number">0</span> : <span class="number">1</span>;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="type">char</span>* errstr = <span class="literal">nullptr</span>;</span><br><span class="line">  <span class="type">int</span> errcode = <span class="built_in">sqlite3_exec</span>(db_, sql.<span class="built_in">data</span>(), c_callback, &amp;callback, &amp;errstr);</span><br><span class="line">  <span class="keyword">if</span> (errcode != SQLITE_OK) &#123;</span><br><span class="line">    std::string msg = errstr ? errstr : <span class="string">&quot;Unknown error&quot;</span>;</span><br><span class="line">    <span class="built_in">sqlite3_free</span>(errstr);</span><br><span class="line">    <span class="keyword">throw</span> std::<span class="built_in">runtime_error</span>(std::format(</span><br><span class="line">        <span class="string">&quot;Failed to execute SQL with callback: &#123;&#125;\nError SQL: &#123;&#125;&quot;</span>, msg, sql));</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="测试一下这个类"><a href="# 测试一下这个类" class="headerlink" title="测试一下这个类"></a>测试一下这个类</h1><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="function">SQLite3 <span class="title">db</span><span class="params">(<span class="string">&quot;test.db&quot;</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    db.<span class="built_in">exec</span>(<span class="string">&quot;create table if not exists users (id integer primary key autoincrement, name text);&quot;</span>);</span><br><span class="line">    db.<span class="built_in">exec</span>(<span class="string">&quot;insert into users (id, name) values (1, &#x27;Alice&#x27;);&quot;</span>);</span><br><span class="line">    db.<span class="built_in">exec</span>(<span class="string">&quot;insert into users (id, name) values (2, &#x27;Bob&#x27;);&quot;</span>);</span><br><span class="line">    db.<span class="built_in">exec</span>(<span class="string">&quot;insert into users (name) values (&#x27;Charlie&#x27;);&quot;</span>);</span><br><span class="line">    db.<span class="built_in">exec</span>(<span class="string">&quot;select * from users;&quot;</span>, [](SQLite3::TableRow row) &#123;</span><br><span class="line">      std::cout &lt;&lt; <span class="string">&quot;User ID: &quot;</span> &lt;&lt; row[<span class="string">&quot;id&quot;</span>] &lt;&lt; <span class="string">&quot;, Name: &quot;</span> &lt;&lt; row[<span class="string">&quot;name&quot;</span>] &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">true</span>;  <span class="comment">// Continue iteration</span></span><br><span class="line">    &#125;);</span><br><span class="line">  &#125; <span class="built_in">catch</span> (<span class="type">const</span> std::exception&amp; e) &#123;</span><br><span class="line">    std::cerr &lt;&lt; e.<span class="built_in">what</span>() &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>运行上述 main 函数后，获得输出如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">User ID: 1, Name: Alice</span><br><span class="line">User ID: 2, Name: Bob</span><br><span class="line">User ID: 3, Name: Charlie</span><br></pre></td></tr></table></figure><p>再次运行该代码，输出如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Failed to execute SQL: UNIQUE constraint failed: users.id</span><br><span class="line">Error SQL: insert into users (id, name) values (1, &#x27;Alice&#x27;);</span><br></pre></td></tr></table></figure><p>测试完毕，这样一个初步的面向对象封装就完成了。</p>]]>
    </content>
    <id>https://keunlas.net/posts/813fa779/</id>
    <link href="https://keunlas.net/posts/813fa779/"/>
    <published>2025-11-21T15:14:50.000Z</published>
    <summary>
      <![CDATA[<h1 id="线程安全问题"><a href="# 线程安全问题" class="headerlink" title="线程安全问题"></a>线程安全问题</h1><p>SQLite3 在编译的时候可以通过添加定义来控制整个库的线程安全问题。</p>
<p>当 <code>S]]>
    </summary>
    <title>《SQLite3》面向对象包装 SQLite3 C/C++ 基础接口</title>
    <updated>2026-03-28T13:24:45.665Z</updated>
  </entry>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <category term="开发" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/"/>
    <category term="SQLite3" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/SQLite3/"/>
    <category term="sqlite" scheme="https://keunlas.net/tags/sqlite/"/>
    <category term="sqlite3" scheme="https://keunlas.net/tags/sqlite3/"/>
    <content>
      <![CDATA[<h1 id="介绍"><a href="# 介绍" class="headerlink" title="介绍"></a>介绍 </h1><p> 最基本的使用 sqlite3 的 c api 还是挺简单的。只需要记住三个接口即可。</p><ul><li><p>打开数据库：<code>sqlite3_open()</code></p></li><li><p>关闭数据库：<code>sqlite3_close()</code></p></li><li><p>执行 SQL 语句：<code>sqlite3_exec()</code></p></li></ul><h1 id="开启数据库"><a href="# 开启数据库" class="headerlink" title="开启数据库"></a>开启数据库 </h1><p> 先来看看如何开启数据库，我们需要提供两个参数，数据库名称和一个 sqlite3 指针的指针。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sqlite3_open</span><span class="params">(</span></span><br><span class="line"><span class="params">  <span class="type">const</span> <span class="type">char</span> *filename,   <span class="comment">/* Database filename (UTF-8) */</span></span></span><br><span class="line"><span class="params">  sqlite3 **ppDb          <span class="comment">/* OUT: SQLite db handle */</span></span></span><br><span class="line"><span class="params">)</span>;</span><br></pre></td></tr></table></figure><p>具体的使用基本如下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">char</span>* db_name = <span class="string">&quot;test.db&quot;</span>;</span><br><span class="line">sqlite3* db;</span><br><span class="line">sqlite3_open(db_name, &amp;db);</span><br></pre></td></tr></table></figure><p>SQLite3 还提供了可以更加精细的控制打开数据库方式的接口：<code>sqlite3_open_v2()</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sqlite3_open_v2</span><span class="params">(</span></span><br><span class="line"><span class="params">  <span class="type">const</span> <span class="type">char</span> *filename,   <span class="comment">/* Database filename (UTF-8) */</span></span></span><br><span class="line"><span class="params">  sqlite3 **ppDb,         <span class="comment">/* OUT: SQLite db handle */</span></span></span><br><span class="line"><span class="params">  <span class="type">int</span> flags,              <span class="comment">/* Flags */</span></span></span><br><span class="line"><span class="params">  <span class="type">const</span> <span class="type">char</span> *zVfs        <span class="comment">/* Name of VFS module to use */</span></span></span><br><span class="line"><span class="params">)</span>;</span><br></pre></td></tr></table></figure><p>可以看到多了两个参数，可以控制数据库只读或其他更精细的操作。<code>sqlite3_open()</code> 可以看作是下述特定参数 <code>sqlite3_open_v2()</code>。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">char</span>* db_name = <span class="string">&quot;test.db&quot;</span>;</span><br><span class="line">sqlite3* db;</span><br><span class="line">sqlite3_open_v2(db_name, &amp;db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, <span class="number">0</span>);</span><br></pre></td></tr></table></figure><p>具体的 <code>sqlite3_open_v2()</code> 使用可以参考官方文档 <a href="https://sqlite.org/c3ref/open.html">Opening A New Database Connection</a>.</p><h1 id="关闭数据库"><a href="# 关闭数据库" class="headerlink" title="关闭数据库"></a>关闭数据库 </h1><p> 关闭数据库只需要把 <code>sqlite3* db</code> 作为参数传入即可。使用十分简单。</p><p>就像 open 接口有多个版本一样，close 接口也有多个版本。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sqlite3_close</span><span class="params">(sqlite3*)</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">sqlite3_close_v2</span><span class="params">(sqlite3*)</span>;</span><br></pre></td></tr></table></figure><p>主要区别是，当 db 还有某些未完成的任务时，两个接口会有不同的行为。</p><p><code>sqlite3_close</code> 会返回 <code>SQLITE_BUSY</code>。</p><p><code>sqlite3_close_v2</code> 会返回 <code>SQLITE_OK</code>。但不会立即释放数据库连接，而是将数据库连接标记为不可用的“僵尸”状态，并安排在所有预处理语句完成、所有 BLOB 句柄关闭以及所有备份操作结束后自动释放数据库连接。</p><h1 id="执行 -SQL- 语句"><a href="# 执行 -SQL- 语句" class="headerlink" title="执行 SQL 语句"></a>执行 SQL 语句</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sqlite3_exec</span><span class="params">(</span></span><br><span class="line"><span class="params">  sqlite3* db,                                  <span class="comment">/* 数据库连接 */</span></span></span><br><span class="line"><span class="params">  <span class="type">const</span> <span class="type">char</span>* sql,                              <span class="comment">/* 要执行的 SQL 语句 */</span></span></span><br><span class="line"><span class="params">  <span class="type">int</span> (*callback)(<span class="type">void</span>*, <span class="type">int</span>, <span class="type">char</span>**, <span class="type">char</span>**),  <span class="comment">/* 回调函数 */</span></span></span><br><span class="line"><span class="params">  <span class="type">void</span>* data,                                   <span class="comment">/* 传递给回调函数的参数 */</span></span></span><br><span class="line"><span class="params">  <span class="type">char</span>** errmsg                                 <span class="comment">/* 错误信息指针 */</span></span></span><br><span class="line"><span class="params">)</span>;</span><br></pre></td></tr></table></figure><p><code>db</code> 是打开的数据库连接。</p><p><code>sql</code> 是要执行的 SQL 语句。</p><p><code>callback</code> 是执行完 SQL 语句后进行的回调函数。（可选参数，不需要可传递空指针）</p><p><code>data</code> 是传给 <code>callback</code> 的第一个参数，可用于传递上下文。（可选参数，不需要可传递空指针）</p><p><code>errmsg</code> 会返回相应的错误信息，如果无错误则被设为空指针。（可选参数，不需要可传递空指针）</p><h2 id="回调函数"><a href="# 回调函数" class="headerlink" title="回调函数"></a>回调函数</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">callback</span><span class="params">(<span class="type">void</span>* context, <span class="type">int</span> col_size, <span class="type">char</span>** col_values, <span class="type">char</span>** col_names)</span>;</span><br></pre></td></tr></table></figure><p>只要理解了这个回调函数会 <strong> 对结果的每一行数据执行一次</strong>，我们就可以轻松的理解这个回调的后面三个和列相关的参数。</p><ul><li><code>context</code>：从 sqlite3_exec() 传递过来的用户数据</li><li><code>col_size</code>：结果行的列数</li><li><code>col_values</code>：列值的字符串数组</li><li><code>col_names</code>：列名的字符串数组</li></ul><p>返回值为 <code>0</code> 时，继续查询。</p><p>返回值为 <code>1</code> 时，终止查询。</p>]]>
    </content>
    <id>https://keunlas.net/posts/8f11705a/</id>
    <link href="https://keunlas.net/posts/8f11705a/"/>
    <published>2025-11-21T15:08:25.000Z</published>
    <summary>
      <![CDATA[<h1 id="介绍"><a href="# 介绍" class="headerlink" title="介绍"></a>介绍 </h1><p> 最基本的使用 sqlite3 的 c api 还是挺简单的。只需要记住三个接口即可。</p>
<ul>
<li><p>打开数据库：<c]]>
    </summary>
    <title>《SQLite3》SQLite3 C/C++ 基础接口</title>
    <updated>2026-03-28T13:24:45.665Z</updated>
  </entry>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <category term="开发" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/"/>
    <category term="SDL3" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/SDL3/"/>
    <category term="sdl" scheme="https://keunlas.net/tags/sdl/"/>
    <category term="sdl3" scheme="https://keunlas.net/tags/sdl3/"/>
    <content>
      <![CDATA[<h1 id="渲染第一个 -SDL- 窗口"><a href="# 渲染第一个 -SDL- 窗口" class="headerlink" title="渲染第一个 SDL 窗口"></a>渲染第一个 SDL 窗口 </h1><p> 首先我们从一个简单的例子讲起，我们渲染一个绿色背景的窗口。</p><p>基本步骤就是创建窗口和渲染器，然后在循环中不断的渲染窗口并展示。</p><p><code>SDL_Init</code>，<code>SDL_CreateWindow</code> 和 <code>SDL_CreateRenderer</code> 拥有 bool 类型的返回值，下列代码中省略了返回值判断。</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;SDL3/SDL.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>* argv[])</span> </span>&#123;</span><br><span class="line">  <span class="built_in">SDL_Init</span>(SDL_INIT_VIDEO); <span class="comment">// 初始化 SDL</span></span><br><span class="line">  SDL_Window* window = <span class="built_in">SDL_CreateWindow</span>(<span class="string">&quot;Hello World&quot;</span>, <span class="number">800</span>, <span class="number">600</span>, <span class="number">0</span>);  <span class="comment">// 创建窗口</span></span><br><span class="line">  SDL_Renderer* renderer = <span class="built_in">SDL_CreateRenderer</span>(window, <span class="literal">nullptr</span>); <span class="comment">// 创建渲染器</span></span><br><span class="line"></span><br><span class="line">  SDL_Event e;</span><br><span class="line">  <span class="type">bool</span> quit = <span class="literal">false</span>;</span><br><span class="line">  <span class="keyword">while</span> (!quit) &#123;</span><br><span class="line">    <span class="keyword">while</span> (<span class="built_in">SDL_PollEvent</span>(&amp;e)) &#123;</span><br><span class="line">      <span class="keyword">if</span> (e.type == SDL_EVENT_QUIT) &#123;</span><br><span class="line">        quit = <span class="literal">true</span>;  <span class="comment">// 当获取到 QUIT 事件时， 终止循环</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">SDL_SetRenderDrawColor</span>(renderer, <span class="number">0</span>, <span class="number">255</span>, <span class="number">0</span>, <span class="number">255</span>); <span class="comment">// 渲染器的颜色</span></span><br><span class="line">    <span class="built_in">SDL_RenderClear</span>(renderer);  <span class="comment">// 清空窗口为渲染器的颜色</span></span><br><span class="line">    <span class="built_in">SDL_RenderPresent</span>(renderer);  <span class="comment">// 展示渲染好的窗口</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 清理资源</span></span><br><span class="line">  <span class="built_in">SDL_DestroyRenderer</span>(renderer);</span><br><span class="line">  <span class="built_in">SDL_DestroyWindow</span>(window);</span><br><span class="line">  <span class="built_in">SDL_Quit</span>();</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="更加的模块化 -SDL3"><a href="# 更加的模块化 -SDL3" class="headerlink" title="更加的模块化 SDL3"></a>更加的模块化 SDL3</h1><p>SDL3 中只需要 <code>#define SDL_MAIN_USE_CALLBACKS 1</code> 并 <code>#include &lt;SDL3/SDL_main.h&gt;</code> 即可使用回调函数代替 main 函数，从而更加方便的编写程序。</p><p>最关键的四个回调函数为：</p><ul><li>程序启动时执行：<code>SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]);</code></li><li>有新事件时执行：<code>SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event);</code></li><li>程序每帧都执行：<code>SDL_AppResult SDL_AppIterate(void *appstate);</code></li><li>程序退出时执行：<code>void SDL_AppQuit(void *appstate, SDL_AppResult result);</code></li></ul><p>具体代码结构如下：</p><figure class="highlight cxx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> SDL_MAIN_USE_CALLBACKS 1 <span class="comment">// 必须设置这个宏</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;SDL3/SDL.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;SDL3/SDL_main.h&gt;</span> <span class="comment">// 并且引入这个头文件</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> SDL_Window *window = <span class="literal">nullptr</span>;</span><br><span class="line"><span class="type">static</span> SDL_Renderer *renderer = <span class="literal">nullptr</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 当程序启动时执行 SDL_AppInit 函数</span></span><br><span class="line"><span class="function">SDL_AppResult <span class="title">SDL_AppInit</span><span class="params">(<span class="type">void</span> **appstate, <span class="type">int</span> argc, <span class="type">char</span> *argv[])</span> </span>&#123;</span><br><span class="line">  <span class="built_in">SDL_Init</span>(SDL_INIT_VIDEO);</span><br><span class="line">  window = <span class="built_in">SDL_CreateWindow</span>(<span class="string">&quot;Hello World&quot;</span>, <span class="number">800</span>, <span class="number">600</span>, <span class="number">0</span>);</span><br><span class="line">  renderer = <span class="built_in">SDL_CreateRenderer</span>(window, <span class="literal">nullptr</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> SDL_APP_CONTINUE;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 当新的事件发生时触发 SDL_AppEvent 函数</span></span><br><span class="line"><span class="function">SDL_AppResult <span class="title">SDL_AppEvent</span><span class="params">(<span class="type">void</span> *appstate, SDL_Event *event)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (event-&gt;type == SDL_EVENT_QUIT) &#123;</span><br><span class="line">    <span class="keyword">return</span> SDL_APP_SUCCESS;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> SDL_APP_CONTINUE;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 每帧运行一次 SDL_AppIterate 函数</span></span><br><span class="line"><span class="function">SDL_AppResult <span class="title">SDL_AppIterate</span><span class="params">(<span class="type">void</span> *appstate)</span> </span>&#123;</span><br><span class="line">  <span class="built_in">SDL_SetRenderDrawColor</span>(renderer, <span class="number">0</span>, <span class="number">255</span>, <span class="number">0</span>, <span class="number">255</span>);</span><br><span class="line">  <span class="built_in">SDL_RenderClear</span>(renderer);</span><br><span class="line">  <span class="built_in">SDL_RenderPresent</span>(renderer);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> SDL_APP_CONTINUE;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 当程序退出时执行 SDL_AppQuit 函数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">SDL_AppQuit</span><span class="params">(<span class="type">void</span> *appstate, SDL_AppResult result)</span> </span>&#123;</span><br><span class="line">  std::cerr &lt;&lt; <span class="string">&quot;SDL_AppQuit.&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://keunlas.net/posts/1d11277a/</id>
    <link href="https://keunlas.net/posts/1d11277a/"/>
    <published>2025-10-05T21:45:51.000Z</published>
    <summary>
      <![CDATA[<h1 id="渲染第一个 -SDL- 窗口"><a href="# 渲染第一个 -SDL- 窗口" class="headerlink" title="渲染第一个 SDL 窗口"></a>渲染第一个 SDL 窗口 </h1><p> 首先我们从一个简单的例子讲起，我们渲染一个绿色]]>
    </summary>
    <title>《SDL3》创建第一个窗口</title>
    <updated>2026-03-28T13:24:45.661Z</updated>
  </entry>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <category term="开发" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/"/>
    <category term="通用知识" scheme="https://keunlas.net/categories/%E5%BC%80%E5%8F%91/%E9%80%9A%E7%94%A8%E7%9F%A5%E8%AF%86/"/>
    <category term="git" scheme="https://keunlas.net/tags/git/"/>
    <category term="gitignore" scheme="https://keunlas.net/tags/gitignore/"/>
    <content>
      <![CDATA[<p>虽然已经用了多年的 git, 但是至今都没怎么好好的总结一下 ignore 规则。今天心血来潮，重新仔细的总结一下 gitignore 到底怎么好好的去写，并记录一下 gitignore 的白名单写法。</p><h1 id="基础规则"><a href="# 基础规则" class="headerlink" title="基础规则"></a>基础规则 </h1><p> 首先是 gitignore 的基础规则。基础规则的总结，我参考了这篇文章 <a href="https://www.freecodecamp.org/news/gitignore-file-how-to-ignore-files-and-folders-in-git/">.gitignore File – How to Ignore Files and Folders in Git</a>. 不过参考文章中有些操作在我所使用的 Archlinux 中无法复现, 所以下面的总结以我自己的实际操作为基础。</p><h2 id="如何在 -Git- 中忽略一个文件或文件夹"><a href="# 如何在 -Git- 中忽略一个文件或文件夹" class="headerlink" title="如何在 Git 中忽略一个文件或文件夹"></a>如何在 Git 中忽略一个文件或文件夹 </h2><h3 id="如何忽略一个文件或目录"><a href="# 如何忽略一个文件或目录" class="headerlink" title="如何忽略一个文件或目录"></a> 如何忽略一个文件或目录</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">/text.txt           # 忽略根目录下 text.txt 文件</span><br><span class="line">/test/text.txt      # 忽略根目录下 test 目录中的 text.txt 文件</span><br><span class="line"></span><br><span class="line">text.txt            # 忽略所有名为 text.txt 的文件和目录</span><br><span class="line">test/               # 忽略所有名为 test 的目录</span><br><span class="line">test                # 忽略所有名为 test 的文件和目录</span><br><span class="line"></span><br><span class="line">*test*              # 忽略所有名字带有 test 的文件和目录</span><br><span class="line">img*                # 忽略所有名字开头是 img 的文件和目录</span><br><span class="line">*.md                # 忽略所有名字结尾是 .md 的文件和目录</span><br></pre></td></tr></table></figure><h3 id="如何不忽略一个文件或目录"><a href="# 如何不忽略一个文件或目录" class="headerlink" title="如何不忽略一个文件或目录"></a>如何不忽略一个文件或目录 </h3><p> 加入我们忽略了所有 md 文件, 但唯独不忽略 README.md 的情况, 如下所示.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">*.md                # 忽略所有名字结尾是 .md 的文件和目录</span><br><span class="line">!README.md          # 不忽略所有名字是 README.md 的文件和目录</span><br></pre></td></tr></table></figure><h3 id="无法排除已经被忽略的目录内的一个文件"><a href="# 无法排除已经被忽略的目录内的一个文件" class="headerlink" title="无法排除已经被忽略的目录内的一个文件"></a>无法排除已经被忽略的目录内的一个文件</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">test/               # 忽略所有名字带有 test 的目录</span><br><span class="line">!test/example.md    # 试图在被忽略的目录内排除一个文件是行不通的</span><br></pre></td></tr></table></figure><h2 id="如何忽略以前提交的文件"><a href="# 如何忽略以前提交的文件" class="headerlink" title="如何忽略以前提交的文件"></a>如何忽略以前提交的文件 </h2><p> 假如你不小心把 .build 文件提交了, 现在想去除这个文件. 过程如下所示.</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment"># 给 .gitignore 添加 .build 文件</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;.build&quot;</span> &gt;&gt; .gitignore</span><br><span class="line"></span><br><span class="line"><span class="comment"># 从 git 版本库中去除该文件</span></span><br><span class="line">git <span class="built_in">rm</span> --cached .build</span><br><span class="line"></span><br><span class="line"><span class="comment"># 暂存新的 .gitignore 并提交</span></span><br><span class="line">git add .gitignore</span><br><span class="line">git commit -m <span class="string">&quot; 更新了 .gitignore 文件 &quot;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="白名单模式"><a href="# 白名单模式" class="headerlink" title="白名单模式"></a>白名单模式 </h1><p> 一般来说 gitignore 是使用黑名单模式，也就是写在 ignore 中的项目会被忽略，但是有些时候使用黑名单模式会有一些疏漏，当项目逐渐庞大起来，难免会有一些遗漏，将一些临时的文件和不希望添加入 git 管理的文件加入 git 中。这个时候白名单模式的 gitignore 能够实现更加精细的管理。</p><p>假设我们有以下结构的 C++ 项目需要管理：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">your-project-dir</span><br><span class="line">├── .gitignore  # gitignore 文件</span><br><span class="line">├── build/      # 构建项目的临时目录</span><br><span class="line">├── docs/       # 放置各种文档</span><br><span class="line">├── include/    # 放置 .h 头文件</span><br><span class="line">├── README.md   # 自述文档</span><br><span class="line">└── src/        # 放置 .cpp 代码文件</span><br></pre></td></tr></table></figure><h2 id="首先忽略全部文件，并取消忽略目录"><a href="# 首先忽略全部文件，并取消忽略目录" class="headerlink" title="首先忽略全部文件，并取消忽略目录"></a><strong>首先忽略全部文件，并取消忽略目录 </strong></h2><p> 白名单模式的第一步。这里取消忽略目录，是因为被忽略目录下的文件是必定被忽略的，为了能够指定不忽略的文件，需要取消忽略目录。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line">!*/</span><br></pre></td></tr></table></figure><h2 id="忽略不想要的目录 -（可选）"><a href="# 忽略不想要的目录 -（可选）" class="headerlink" title="忽略不想要的目录 （可选）"></a><strong>忽略不想要的目录 </strong> （可选）</h2><p> 因为 build 目录完全是一个临时目录，我不想提交里面的任何文件，所以可以直接忽略掉。如果这个目录里有某些特定的文件需要提交，则不应该忽略这个目录。</p><p>之所以这是一个可选的操作，是因为在上一步忽略了所有文件之后，所有的目录内都没有需要提交的文件，在 git 中这样的“空目录”不会被提交。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/build/</span><br></pre></td></tr></table></figure><h2 id="取消忽略特定的文件"><a href="# 取消忽略特定的文件" class="headerlink" title="取消忽略特定的文件"></a><strong>取消忽略特定的文件 </strong></h2><p> 有些文件我们希望必须提交的，我们可以直接取消忽略这些文件。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">!.gitignore</span><br><span class="line">!README.md</span><br></pre></td></tr></table></figure><p>这样之后，任何目录下的 .gitignore 和 README.md 文件都会被提交上去。</p><h2 id="取消忽略特定目录下的全部文件"><a href="# 取消忽略特定目录下的全部文件" class="headerlink" title="取消忽略特定目录下的全部文件"></a><strong>取消忽略特定目录下的全部文件 </strong></h2><p> 我希望提交 docs 目录下的所有文件，包括其子目录下的所有文件。通过下面这种写法，可以取消忽略 docs 目录下的所有文件，并递归的忽略其子目录下的所有文件。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">!/docs/**/*</span><br></pre></td></tr></table></figure><h2 id="取消忽略特定目录下的特定文件"><a href="# 取消忽略特定目录下的特定文件" class="headerlink" title="取消忽略特定目录下的特定文件"></a><strong>取消忽略特定目录下的特定文件 </strong></h2><p> 有的目录我只希望提交特定类型的文件，例如 src 目录下的 .cpp 代码文件和 include 目录下的 .h 头文件。</p><p>下面这种写法取消忽略了对应目录下所有特定后缀的文件，并递归的忽略其子目录下所有特定后缀的文件。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">!/include/be/**/*.h</span><br><span class="line">!/src/be/**/*.cpp</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="# 总结" class="headerlink" title="总结"></a>总结 </h2><p> 最后的白名单 gitignore 文件看上去是这样的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line">!*/</span><br><span class="line"></span><br><span class="line">/build/</span><br><span class="line"></span><br><span class="line">!.gitignore</span><br><span class="line">!README.md</span><br><span class="line"></span><br><span class="line">!/docs/**/*</span><br><span class="line">!/include/be/**/*.h</span><br><span class="line">!/src/be/**/*.cpp</span><br></pre></td></tr></table></figure><p>在比较复杂的项目中，或者需要精细控制提交的文件时，白名单模式的 ignore 文件是真的很好用。</p>]]>
    </content>
    <id>https://keunlas.net/posts/a41423c1/</id>
    <link href="https://keunlas.net/posts/a41423c1/"/>
    <published>2025-09-26T18:34:18.000Z</published>
    <summary>
      <![CDATA[<p>虽然已经用了多年的 git, 但是至今都没怎么好好的总结一下 ignore 规则。今天心血来潮，重新仔细的总结一下 gitignore 到底怎么好好的去写，并记录一下 gitignore 的白名单写法。</p>
<h1 id="基础规则"><a href="# 基础规则"]]>
    </summary>
    <title>白名单模式的 gitignore 配置</title>
    <updated>2026-03-28T13:24:45.665Z</updated>
  </entry>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <category term="折腾" scheme="https://keunlas.net/categories/%E6%8A%98%E8%85%BE/"/>
    <category term="mihomo" scheme="https://keunlas.net/tags/mihomo/"/>
    <category term="archlinux" scheme="https://keunlas.net/tags/archlinux/"/>
    <content>
      <![CDATA[<p>因为在 Archlinux 上使用 Clash Verge Rev 经常会出现一些奇怪的问题，比如说 service 无法运行，界面卡顿加载不出来，甚至会直接卡死。所以很早之前我就有了直接跑纯内核的念头。</p><p>故现在我终于开始尝试直接跑纯 Mihomo 内核，目前是已经完成了所有的配置，普通模式和 Tun 模式都可以正常使用。现将过程记录如下。</p><p>由于我是在 Archlinux 上进行的安装，我可以确保在 Archlinux 上以下操作全部经过检验。</p><h1 id="安装 -mihomo- 核心及其依赖"><a href="# 安装 -mihomo- 核心及其依赖" class="headerlink" title="安装 mihomo 核心及其依赖"></a>安装 mihomo 核心及其依赖 </h1><p> 实际上包管理器会自动处理依赖，所以不用担心。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yay -S mihomo</span><br></pre></td></tr></table></figure><h1 id="安装 -metacubexd- 界面"><a href="# 安装 -metacubexd- 界面" class="headerlink" title="安装 metacubexd 界面"></a>安装 metacubexd 界面 </h1><p> 为了能够在 web 端方便的临时调整配置，以及可视化连接及流量，我推荐安装 metacubexd 这个界面。</p><p>如果你配置了 archlinuxcn 源，可以直接 pacman 安装预编译版本。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> pacman -S metacubexd-bin </span><br></pre></td></tr></table></figure><p>也可以在 AUR 中安装，metacubexd-bin 是预编译版本，metacubexd 是源码需要本机上编译。我比较推荐预编译版本。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yay -S metacubexd-bin</span><br></pre></td></tr></table></figure><h1 id="启动守护进程"><a href="# 启动守护进程" class="headerlink" title="启动守护进程"></a>启动守护进程</h1><p>AUR 中提供的 mihomo 软件包里面自带了 systemd 守护进程 mihomo.service，我们需要手动 enable 让 mihomo 内核可以开机自启。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> mihomo.service</span><br></pre></td></tr></table></figure><p>然后启动 mihomo 内核进行下一步工作。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl start mihomo.service</span><br></pre></td></tr></table></figure><h1 id="配置文件"><a href="# 配置文件" class="headerlink" title="配置文件"></a>配置文件 </h1><p> 通过查看守护进程文件 &#x2F;etc&#x2F;systemd&#x2F;system&#x2F;multi-user.target.wants&#x2F;mihomo.service 可以看到我的 mihomo 的工作目录为 &#x2F;etc&#x2F;mihomo, mihomo 内核的配置文件在 &#x2F;etc&#x2F;mihomo&#x2F;config.yaml 中，我们需要修改这个文件来配置我们的 mihomo 内核。</p><p>config.yaml 这个文件就是最主要的配置文件，只不过我们需要修改一些内容。来适合我的使用习惯。</p><p>首先把 config.yaml 中的所有内容清空，然后把机场给出的配置文件整个的复制过来。</p><p>接下来就是修改修改了。</p><h2 id="修改端口"><a href="# 修改端口" class="headerlink" title="修改端口"></a>修改端口 </h2><p> 因为 Clash Verge Rev 的默认 mixed-port 是 7897, 我的很多软件的代理都设置为了这个端口，所以我也依旧修改 mixed-port 为 7897.</p><p>并且我不喜欢开启局域网访问，所以我将 allow-lan 修改为 false.</p><p>现在，我的 config.yaml 大概是这个样子。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mixed-port:</span> <span class="number">7897</span></span><br><span class="line"><span class="attr">port:</span> <span class="number">7890</span></span><br><span class="line"><span class="attr">socks-port:</span> <span class="number">7891</span></span><br><span class="line"><span class="attr">allow-lan:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">mode:</span> <span class="string">Rule</span></span><br><span class="line"><span class="attr">log-level:</span> <span class="string">info</span></span><br><span class="line"><span class="attr">external-controller:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:9090</span></span><br><span class="line"></span><br><span class="line"><span class="attr">proxies:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br><span class="line"><span class="attr">proxy-groups:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br></pre></td></tr></table></figure><p>我们需要重启 mihomo 内核，让配置生效。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart mihomo.service</span><br></pre></td></tr></table></figure><p>这个时候，mihomo 就已经可以正常的使用了。</p><p>但是 Tun 模式目前还用不了，接下来我们继续设置。</p><h2 id="配置 -metacubexd- 界面"><a href="# 配置 -metacubexd- 界面" class="headerlink" title="配置 metacubexd 界面"></a>配置 metacubexd 界面</h2><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 前端控制器界面 (archlinuxcn 源中的 metacubexd)</span></span><br><span class="line"><span class="attr">external-ui:</span> <span class="string">/usr/share/metacubexd</span></span><br></pre></td></tr></table></figure><p>只需要在 config.yaml 中加上这一行就可以，archlinuxcn 源中的 metacubexd-bin 的目录是在 &#x2F;usr&#x2F;share&#x2F;metacubexd 中。AUR 中的我没有尝试过，大家下载下来之后可以使用 <code>pacman -Ql metacubexd-bin</code> 查看一下具体的路径。</p><p>然后我们需要重启 mihomo 内核，让配置生效。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart mihomo.service</span><br></pre></td></tr></table></figure><p>然然后我们就可以在浏览器中通过配置文件中 <code>external-controller: 127.0.0.1:9090</code> 的地址来访问 metacubexd 界面了。</p><p>记得加上 <code>/ui</code> 这个后缀，否则进不去 metacubexd 的界面。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://127.0.0.1:9090/ui</span><br></pre></td></tr></table></figure><p>那么现在我们的配置就都完成的差不多了， config.yaml 大概是这个样子。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mixed-port:</span> <span class="number">7897</span></span><br><span class="line"><span class="attr">port:</span> <span class="number">7890</span></span><br><span class="line"><span class="attr">socks-port:</span> <span class="number">7891</span></span><br><span class="line"><span class="attr">allow-lan:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">mode:</span> <span class="string">Rule</span></span><br><span class="line"><span class="attr">log-level:</span> <span class="string">info</span></span><br><span class="line"><span class="attr">external-controller:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:9090</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 前端控制器界面 (archlinuxcn 源中的 metacubexd)</span></span><br><span class="line"><span class="attr">external-ui:</span> <span class="string">/usr/share/metacubexd</span></span><br><span class="line"></span><br><span class="line"><span class="attr">proxies:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br><span class="line"><span class="attr">proxy-groups:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br></pre></td></tr></table></figure><h1 id="高级配置"><a href="# 高级配置" class="headerlink" title="高级配置"></a>高级配置 </h1><h2 id="DNS- 配置"><a href="#DNS- 配置" class="headerlink" title="DNS 配置"></a>DNS 配置</h2><p> 根据我的测试，不配置 dns 就无法使用 Tun 模式，所以我们这里直接给出我已经配置好的配置，大家可以直接复制粘贴到 config.yaml 中。</p><p>具体的选项起到什么作用其实还是很直接的，有想自己自定义的可以查看官方 Wiki 上的配置选项。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># DNS</span></span><br><span class="line"><span class="attr">dns:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">ipv6:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">listen:</span> <span class="number">0.0</span><span class="number">.0</span><span class="number">.0</span><span class="string">:53</span></span><br><span class="line">  <span class="attr">enhanced-mode:</span> <span class="string">fake-ip</span> <span class="comment"># redir-host</span></span><br><span class="line">  <span class="attr">fake-ip-range:</span> <span class="number">198.18</span><span class="number">.0</span><span class="number">.1</span><span class="string">/16</span></span><br><span class="line">  <span class="attr">fake-ip-filter:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">geosite:fakeip-filter</span></span><br><span class="line">  <span class="attr">default-nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">system</span></span><br><span class="line">  <span class="attr">nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://doh.pub/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://dns.alidns.com/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://dns.google/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://cloudflare-dns.com/dns-query</span></span><br><span class="line">  <span class="attr">proxy-server-nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://doh.pub/dns-query</span></span><br></pre></td></tr></table></figure><h2 id="Tun- 模式配置"><a href="#Tun- 模式配置" class="headerlink" title="Tun 模式配置"></a>Tun 模式配置</h2><p>Tun 模式的具体配置我没有在 config.yaml 中进行配置，而是直接使用的默认配置，在 web 界面上直接开启 Tun 模式即可使用。</p><h2 id="其他配置"><a href="# 其他配置" class="headerlink" title="其他配置"></a>其他配置 </h2><p> 我还从 Wiki 上找了几个比较有用的配置</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># web 界面的登录密码</span></span><br><span class="line"><span class="comment"># (因为我这里监听的 127.0.0.1 只有本机能够访问, 暂不设置)</span></span><br><span class="line"><span class="comment"># secret: &quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#【Mihomo 专属】TCP 连接并发，如果域名解析结果对应多个 IP，</span></span><br><span class="line"><span class="comment"># 并发所有 IP，选择握手最快的 IP 进行连接</span></span><br><span class="line"><span class="attr">tcp-concurrent:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置缓存 (代理中选择的节点和 fake-ip 缓存)</span></span><br><span class="line"><span class="attr">profile:</span></span><br><span class="line">  <span class="attr">store-selected:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">store-fake-ip:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#【Mihomo 专属】使用 geoip.dat 数据库(默认：false 使用 mmdb 数据库)</span></span><br><span class="line"><span class="attr">geodata-mode:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr">geo-auto-update:</span> <span class="literal">true</span> <span class="comment"># 自动更新</span></span><br><span class="line"><span class="attr">geo-update-interval:</span> <span class="number">24</span> <span class="comment"># 更新间隔 24 小时</span></span><br><span class="line"><span class="attr">geox-url:</span> <span class="comment"># 下载 geoip.dat 数据库的地址</span></span><br><span class="line">  <span class="attr">geoip:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geoip-all.dat&quot;</span></span><br><span class="line">  <span class="attr">geosite:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geosite-all.dat&quot;</span></span><br><span class="line">  <span class="attr">mmdb:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-all.mmdb&quot;</span></span><br><span class="line">  <span class="attr">asn:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-ASN-all.mmdb&quot;</span></span><br></pre></td></tr></table></figure><h1 id="最终配置"><a href="# 最终配置" class="headerlink" title="最终配置"></a>最终配置 </h1><p> 最后的配置大概长这个样子。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">mixed-port:</span> <span class="number">7897</span></span><br><span class="line"><span class="attr">port:</span> <span class="number">7890</span></span><br><span class="line"><span class="attr">socks-port:</span> <span class="number">7891</span></span><br><span class="line"><span class="attr">allow-lan:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">mode:</span> <span class="string">Rule</span></span><br><span class="line"><span class="attr">log-level:</span> <span class="string">info</span></span><br><span class="line"><span class="attr">external-controller:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:9090</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 前端控制器界面 (archlinuxcn 源中的 metacubexd)</span></span><br><span class="line"><span class="attr">external-ui:</span> <span class="string">/usr/share/metacubexd</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># web 界面的登录密码</span></span><br><span class="line"><span class="comment"># (因为我这里监听的 127.0.0.1 只有本机能够访问, 暂不设置)</span></span><br><span class="line"><span class="comment"># secret: &quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#【Mihomo 专属】TCP 连接并发，如果域名解析结果对应多个 IP，</span></span><br><span class="line"><span class="comment"># 并发所有 IP，选择握手最快的 IP 进行连接</span></span><br><span class="line"><span class="attr">tcp-concurrent:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置缓存 (代理中选择的节点和 fake-ip 缓存)</span></span><br><span class="line"><span class="attr">profile:</span></span><br><span class="line">  <span class="attr">store-selected:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">store-fake-ip:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#【Mihomo 专属】使用 geoip.dat 数据库(默认：false 使用 mmdb 数据库)</span></span><br><span class="line"><span class="attr">geodata-mode:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr">geo-auto-update:</span> <span class="literal">true</span> <span class="comment"># 自动更新</span></span><br><span class="line"><span class="attr">geo-update-interval:</span> <span class="number">24</span> <span class="comment"># 更新间隔 24 小时</span></span><br><span class="line"><span class="attr">geox-url:</span> <span class="comment"># 下载 geoip.dat 数据库的地址</span></span><br><span class="line">  <span class="attr">geoip:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geoip-all.dat&quot;</span></span><br><span class="line">  <span class="attr">geosite:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geosite-all.dat&quot;</span></span><br><span class="line">  <span class="attr">mmdb:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-all.mmdb&quot;</span></span><br><span class="line">  <span class="attr">asn:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-ASN-all.mmdb&quot;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># DNS</span></span><br><span class="line"><span class="attr">dns:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">ipv6:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">listen:</span> <span class="number">0.0</span><span class="number">.0</span><span class="number">.0</span><span class="string">:53</span></span><br><span class="line">  <span class="attr">enhanced-mode:</span> <span class="string">fake-ip</span> <span class="comment"># redir-host</span></span><br><span class="line">  <span class="attr">fake-ip-range:</span> <span class="number">198.18</span><span class="number">.0</span><span class="number">.1</span><span class="string">/16</span></span><br><span class="line">  <span class="attr">fake-ip-filter:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">geosite:fakeip-filter</span></span><br><span class="line">  <span class="attr">default-nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">system</span></span><br><span class="line">  <span class="attr">nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://doh.pub/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://dns.alidns.com/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://dns.google/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://cloudflare-dns.com/dns-query</span></span><br><span class="line">  <span class="attr">proxy-server-nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://doh.pub/dns-query</span></span><br><span class="line">  <span class="comment"># nameserver-policy:</span></span><br><span class="line">  <span class="comment">#   &quot;geosite:cn,private&quot;:</span></span><br><span class="line">  <span class="comment">#     - https://doh.pub/dns-query</span></span><br><span class="line">  <span class="comment">#     - https://dns.alidns.com/dns-query</span></span><br><span class="line">  <span class="comment">#   &quot;geosite:ads&quot;:</span></span><br><span class="line">  <span class="comment">#     - rcode://success</span></span><br><span class="line">  <span class="comment">#   &quot;geosite:!cn,!private,!ads&quot;:</span></span><br><span class="line">  <span class="comment">#     - https://dns.google/dns-query</span></span><br><span class="line">  <span class="comment">#     - https://cloudflare-dns.com/dns-query</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="attr">proxies:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br><span class="line"><span class="attr">proxy-groups:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line">  <span class="comment"># ...</span></span><br></pre></td></tr></table></figure><p>在 dns 配置中，可以配置 nameserver-policy 来实现不同的域名使用不同的 DNS 服务器。可以非常有效的解决 dns 泄漏问题，但是不知道为什么，我用起来网址解析的非常慢，所以我没有使用这个配置，而是注释掉了。</p><p>现在我的配置已经可以正常使用了，无论是走端口代理，还是直接 Tun 模式接管一切都没有任何问题了。</p><h1 id="手写脚本实现一键更新订阅"><a href="# 手写脚本实现一键更新订阅" class="headerlink" title="手写脚本实现一键更新订阅"></a>手写脚本实现一键更新订阅 </h1><p> 首先把需要附加的配置写在 append.yaml 中。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># append.yaml</span></span><br><span class="line"></span><br><span class="line"><span class="attr">mixed-port:</span> <span class="number">7897</span></span><br><span class="line"><span class="attr">port:</span> <span class="number">7890</span></span><br><span class="line"><span class="attr">socks-port:</span> <span class="number">7891</span></span><br><span class="line"><span class="attr">allow-lan:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">mode:</span> <span class="string">Rule</span></span><br><span class="line"><span class="attr">log-level:</span> <span class="string">info</span></span><br><span class="line"><span class="attr">external-controller:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:9090</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 前端控制器界面 (archlinuxcn 源中的 metacubexd)</span></span><br><span class="line"><span class="attr">external-ui:</span> <span class="string">/usr/share/metacubexd</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># web 界面的登录密码</span></span><br><span class="line"><span class="comment"># (因为我这里监听的 127.0.0.1 只有本机能够访问, 暂不设置)</span></span><br><span class="line"><span class="comment"># secret: &quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#【Mihomo 专属】TCP 连接并发，如果域名解析结果对应多个 IP，</span></span><br><span class="line"><span class="comment"># 并发所有 IP，选择握手最快的 IP 进行连接</span></span><br><span class="line"><span class="attr">tcp-concurrent:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置缓存 (代理中选择的节点和 fake-ip 缓存)</span></span><br><span class="line"><span class="attr">profile:</span></span><br><span class="line">  <span class="attr">store-selected:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">store-fake-ip:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#【Mihomo 专属】使用 geoip.dat 数据库(默认：false 使用 mmdb 数据库)</span></span><br><span class="line"><span class="attr">geodata-mode:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr">geo-auto-update:</span> <span class="literal">true</span> <span class="comment"># 自动更新</span></span><br><span class="line"><span class="attr">geo-update-interval:</span> <span class="number">24</span> <span class="comment"># 更新间隔 24 小时</span></span><br><span class="line"><span class="attr">geox-url:</span> <span class="comment"># 下载 geoip.dat 数据库的地址</span></span><br><span class="line">  <span class="attr">geoip:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geoip-all.dat&quot;</span></span><br><span class="line">  <span class="attr">geosite:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geosite-all.dat&quot;</span></span><br><span class="line">  <span class="attr">mmdb:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-all.mmdb&quot;</span></span><br><span class="line">  <span class="attr">asn:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-ASN-all.mmdb&quot;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># DNS</span></span><br><span class="line"><span class="attr">dns:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">ipv6:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">listen:</span> <span class="number">0.0</span><span class="number">.0</span><span class="number">.0</span><span class="string">:53</span></span><br><span class="line">  <span class="attr">enhanced-mode:</span> <span class="string">fake-ip</span> <span class="comment"># redir-host</span></span><br><span class="line">  <span class="attr">fake-ip-range:</span> <span class="number">198.18</span><span class="number">.0</span><span class="number">.1</span><span class="string">/16</span></span><br><span class="line">  <span class="attr">fake-ip-filter:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">geosite:fakeip-filter</span></span><br><span class="line">  <span class="attr">default-nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">system</span></span><br><span class="line">  <span class="attr">nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://doh.pub/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://dns.alidns.com/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://dns.google/dns-query</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://cloudflare-dns.com/dns-query</span></span><br><span class="line">  <span class="attr">proxy-server-nameserver:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">https://doh.pub/dns-query</span></span><br><span class="line">  <span class="comment"># nameserver-policy:</span></span><br><span class="line">  <span class="comment">#   &quot;geosite:cn,private&quot;:</span></span><br><span class="line">  <span class="comment">#     - https://doh.pub/dns-query</span></span><br><span class="line">  <span class="comment">#     - https://dns.alidns.com/dns-query</span></span><br><span class="line">  <span class="comment">#   &quot;geosite:ads&quot;:</span></span><br><span class="line">  <span class="comment">#     - rcode://success</span></span><br><span class="line">  <span class="comment">#   &quot;geosite:!cn,!private,!ads&quot;:</span></span><br><span class="line">  <span class="comment">#     - https://dns.google/dns-query</span></span><br><span class="line">  <span class="comment">#     - https://cloudflare-dns.com/dns-query</span></span><br></pre></td></tr></table></figure><p>因为我的订阅中已经有了一些配置，这些配置会和 append.yaml 中的配置冲突，所以通过 sed 进行删除处理。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取机场配置，去除前 6 行，保存到 tmp.yaml</span></span><br><span class="line">curl -L <span class="string">&#x27;&lt; 你的订阅地址 &gt;&#x27;</span> | sed <span class="string">&#x27;1,6d&#x27;</span> &gt; tmp.yaml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 附加 append.yaml 到 tmp.yaml</span></span><br><span class="line"><span class="built_in">cat</span> append.yaml &gt;&gt; tmp.yaml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 原来配置的备份到 config.yaml.bak</span></span><br><span class="line"><span class="built_in">cp</span> config.yaml config.yaml.bak</span><br><span class="line"></span><br><span class="line"><span class="comment"># 用 tmp.yaml 替换 config.yaml</span></span><br><span class="line"><span class="built_in">cat</span> tmp.yaml &gt; config.yaml</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>之后使用 <code>sudo systemctl restart mihomo</code> 重启一下 mihomo 服务，或者在 web 界面中重新读取一下配置即可完成更新。</p><h1 id="其他"><a href="# 其他" class="headerlink" title="其他"></a>其他</h1><h2 id="mmdb"><a href="#mmdb" class="headerlink" title="mmdb"></a>mmdb</h2><ol><li>第一次启动的时候 mihomo 会下载 mmdb，可能会因为网络问题下载失败，从而没法成功运行。可以先设置好 geox-url 的 cdn 地址，然后重启即可下载成功。</li></ol><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">geox-url:</span> <span class="comment"># 下载 geoip.dat 数据库的地址</span></span><br><span class="line">  <span class="attr">geoip:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geoip-all.dat&quot;</span></span><br><span class="line">  <span class="attr">geosite:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/geosite-all.dat&quot;</span></span><br><span class="line">  <span class="attr">mmdb:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-all.mmdb&quot;</span></span><br><span class="line">  <span class="attr">asn:</span> <span class="string">&quot;https://cdn.jsdelivr.net/gh/DustinWin/ruleset_geodata@mihomo/Country-ASN-all.mmdb&quot;</span></span><br></pre></td></tr></table></figure><h2 id="ssh-in-Tun-mode"><a href="#ssh-in-Tun-mode" class="headerlink" title="ssh in Tun mode"></a>ssh in Tun mode</h2><ol start="2"><li>Tun 模式下 ssh 之类的软件都无法使用，因为连接的 ip 都会变成 198.18.0.1 这个地址。经过评论区中大佬的提醒，我找到了一个解决方法。在 dns 配置的 <code>fake-ip-filter:</code> 这一项中，把想要 ssh 连接的域名和 ip 填上去就行。否则无论是通过域名进行连接还是直接通过 ip 连接，都会连接不上。</li></ol><h2 id="proxy-providers"><a href="#proxy-providers" class="headerlink" title="proxy-providers"></a>proxy-providers</h2><ol start="3"><li>经提醒，纯内核也支持配置订阅连接。经过一番折腾过后，我发现虽然支持订阅连接，但是 proxy-providers 似乎只导入其中的 proxies，但是对我来说 proxy-groups 和 rules 也是非常需要的，故暂不使用此功能。</li></ol><h2 id="external-ui"><a href="#external-ui" class="headerlink" title="external-ui"></a>external-ui</h2><ol start="4"><li>新版的 mihomo 对 web 界面的存放目录有了要求，可能需要将 metacubexd 的存放目录放到符合要求的位置。</li></ol>]]>
    </content>
    <id>https://keunlas.net/posts/a2809040/</id>
    <link href="https://keunlas.net/posts/a2809040/"/>
    <published>2025-04-17T14:01:16.000Z</published>
    <summary>
      <![CDATA[<p>因为在 Archlinux 上使用 Clash Verge Rev 经常会出现一些奇怪的问题，比如说 service 无法运行，界面卡顿加载不出来，甚至会直接卡死。所以很早之前我就有了直接跑纯内核的念头。</p>
<p>故现在我终于开始尝试直接跑纯 Mihomo 内核，目前]]>
    </summary>
    <title>Mihomo 纯内核运行</title>
    <updated>2026-03-28T13:24:45.665Z</updated>
  </entry>
  <entry>
    <author>
      <name>Keunlas</name>
    </author>
    <content>
      <![CDATA[<center> 欢迎来到我的日志 </center><br><center> (｡･ω･)ﾉﾞ </center><br><center> 这里的内容主要和我的学习路线有关 </center><center> 当然也有 Archlinux 的内容 </center><center> 学习是永无止境的 </center><center> 学得越多就越会觉得自己无知 </center><center> 人类终究是有极限的 </center><center> 除非... </center><br><center> 说笑了 </center><center> 总之 </center><center> 全員一層奮励努力せよ！ </center><center>  </center><center>  </center><center>  </center><center>  </center><center>  </center><center>  </center><center>  </center>]]>
    </content>
    <id>https://keunlas.net/posts/4a17b156/</id>
    <link href="https://keunlas.net/posts/4a17b156/"/>
    <published>2025-01-04T05:18:32.000Z</published>
    <summary>
      <![CDATA[<center> 欢迎来到我的日志 </center><br>
<center> (｡･ω･)ﾉﾞ </center><br>

<center> 这里的内容主要和我的学习路线有关 </center>
<center> 当然也有 Archlinux 的内容 </center>
<]]>
    </summary>
    <title>Welcome!</title>
    <updated>2026-03-28T13:24:45.661Z</updated>
  </entry>
</feed>
