<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>重传 on 大飞的博客</title>
    <link>https://www.dafei.me/tags/%E9%87%8D%E4%BC%A0/</link>
    <description>Recent content in 重传 on 大飞的博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 01 Jun 2026 10:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.dafei.me/tags/%E9%87%8D%E4%BC%A0/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>从零写OS（四十三）：TCP 重传 —— 丢包了也能传完</title>
      <link>https://www.dafei.me/posts/os-43-tcp-retransmit/</link>
      <pubDate>Mon, 01 Jun 2026 10:00:00 +0000</pubDate>
      <guid>https://www.dafei.me/posts/os-43-tcp-retransmit/</guid>
      <description>&lt;p&gt;上一章（四十二）修了一堆 busybox 相关的 bug，让 &lt;code&gt;ls&lt;/code&gt;/&lt;code&gt;exec&lt;/code&gt;/&lt;code&gt;wait&lt;/code&gt; 都能正常工作，&lt;code&gt;wget_test&lt;/code&gt; 也能跑通 HTTP。但那时的 TCP 实现有个隐患：&lt;strong&gt;一旦丢包，传输就会永远卡住&lt;/strong&gt;。这一章把重传机制做完整。&lt;/p&gt;
&lt;h2 id=&#34;原代码的问题&#34;&gt;原代码的问题&lt;/h2&gt;
&lt;p&gt;ch42 的 &lt;code&gt;tcp_send_raw&lt;/code&gt; 函数身兼数职：构造 TCP 包、发送、存入发送缓冲区、推进 &lt;code&gt;snd_nxt&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tcp_send_raw&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;tcp_sock_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;s, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt; flags, &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;data, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16_t&lt;/span&gt; dlen) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;发包&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (dlen) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;存&lt;/span&gt; sbuf...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;snd_nxt &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; dlen;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (flags &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; (TCP_SYN &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; TCP_FIN)) s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;seq&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;   &lt;span style=&#34;color:#75715e&#34;&gt;// 推进 seq
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (dlen) s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;seq &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; dlen;                     &lt;span style=&#34;color:#75715e&#34;&gt;// 又推进一次！
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;问题一：&lt;code&gt;seq&lt;/code&gt; 和 &lt;code&gt;snd_nxt&lt;/code&gt; 是两个字段，但都在追踪&amp;quot;下一个要发的序号&amp;quot;，语义重复，而且 &lt;strong&gt;&lt;code&gt;seq&lt;/code&gt; 被推进了两次&lt;/strong&gt;（SYN/FIN 一次、数据一次）。&lt;/p&gt;
&lt;p&gt;问题二：重传时的代码非常丑陋：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; saved_seq &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;seq;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; saved_nxt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;snd_nxt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;seq     &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;snd_una;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;snd_nxt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;snd_una;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tcp_send_raw&lt;/span&gt;(s, TCP_PSH &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; TCP_ACK, rtbuf, chunk);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;snd_nxt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; saved_nxt;   &lt;span style=&#34;color:#75715e&#34;&gt;// 手动恢复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;seq     &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; saved_seq;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种&amp;quot;临时改状态再恢复&amp;quot;的方式容易出错，而且没有指数退避。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
