<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>MiengGiet Blog</title>
  
  <subtitle>学习记录</subtitle>
  <link href="https://ethereal14.github.io/atom.xml" rel="self"/>
  
  <link href="https://ethereal14.github.io/"/>
  <updated>2023-03-12T16:03:10.205Z</updated>
  <id>https://ethereal14.github.io/</id>
  
  <author>
    <name>MiengGiet</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>循序渐进学习开发RISCV-OS</title>
    <link href="https://ethereal14.github.io/2022/01/27/%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0%E5%BC%80%E5%8F%91RISCV-OS/"/>
    <id>https://ethereal14.github.io/2022/01/27/%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0%E5%BC%80%E5%8F%91RISCV-OS/</id>
    <published>2022-01-27T13:57:05.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    <content type="html"><![CDATA[<h1 id="笔记"><a href="#笔记" class="headerlink" title="笔记"></a>笔记</h1><h2 id="算术运算指令"><a href="#算术运算指令" class="headerlink" title="算术运算指令"></a>算术运算指令</h2><table><thead><tr><th>指令</th><th>语法</th><th>描述</th><th>例子</th></tr></thead><tbody><tr><td>add</td><td>add rd, rs1, rs2</td><td>rs1和rs2的值相加，结果保存到rd</td><td>add x5, x6, x7</td></tr><tr><td>sub</td><td>sub rd, rs1, rs2</td><td>rs1的值减去rs2的值，结果保存到rd</td><td>sub x5, x6, x7</td></tr><tr><td>addi</td><td>addi rd, rs1, imm</td><td>rs1的值和imm相加，结果保存到rd</td><td>addi x5, x6, 100</td></tr><tr><td>lui</td><td>lui rd, imm</td><td>构造一个32位的数，高20位存放imm，低12位清零。结果保存到rd</td><td>lui x5, 0x12345</td></tr><tr><td>auipc</td><td>auipc rd, imm</td><td>构造一个32位的数，高20位存放imm，低12位清零。结果和pc相加后保存到rd</td><td>auipc x5, 0x12345</td></tr></tbody></table><table><thead><tr><th>伪指令</th><th>语法</th><th>等价指令</th><th>描述</th><th>例子</th></tr></thead><tbody><tr><td>li</td><td>li rd, imm</td><td>lui和addi的组合</td><td>将立即数imm加载到rd中</td><td>li x5, 0x12345678</td></tr><tr><td>la</td><td>la rd, label</td><td>auipc和addi的组合</td><td>为rd加载一个地址值</td><td>la x5, label</td></tr><tr><td>neg</td><td>neg rd, rs</td><td>sub rd, x0, rs</td><td>对rs中的值取反并将结果存放在rd中</td><td>neg x5, x6</td></tr><tr><td>mv</td><td>mv rd, rs</td><td>addi rd, rs, 0</td><td>将rs中的值拷贝到rd中</td><td>mv x5, x6</td></tr><tr><td>nop</td><td>nop</td><td>addi x0, x0, 0</td><td>什么也不做</td><td>nop</td></tr></tbody></table><h3 id="ADD"><a href="#ADD" class="headerlink" title="ADD"></a>ADD</h3><table><thead><tr><th>语法</th><th>add rd, rs1, rs2</th><th></th></tr></thead><tbody><tr><td><strong>例子</strong></td><td>add x5, x6, x7</td><td>x5 = x6 + x7</td></tr></tbody></table><ul><li>编码格式：<strong>R-type</strong>， 寄存器类型<ul><li>opcode：0110011</li></ul></li><li>符号拓展：最高位(符号位)为1，零扩展：最高位(符号位)为0</li><li>有符号数在计算机中表示：二进制补码</li><li>补码→原码：减一取反</li></ul><h3 id="SUB"><a href="#SUB" class="headerlink" title="SUB"></a>SUB</h3><table><thead><tr><th>语法</th><th>sub rd, rs1, rs2</th><th></th></tr></thead><tbody><tr><td><strong>例子</strong></td><td>sub x5, x6, x7</td><td>x5 = x6 - x7</td></tr></tbody></table><h3 id="ADDI"><a href="#ADDI" class="headerlink" title="ADDI"></a>ADDI</h3><table><thead><tr><th>语法</th><th>addi rd, rs1, IMM</th><th></th></tr></thead><tbody><tr><td><strong>例子</strong></td><td>addi x5, x6, 1</td><td>x5 = x6 + 1</td></tr></tbody></table><ul><li>编码格式：<strong>I-type</strong>，立即数格式<ul><li>opcode：0b0010011</li></ul></li><li>缺陷：<ul><li>immediate立即数占12位</li><li>参与运算时会被<strong>符号拓展</strong>为一个32位的数</li><li>这个立即数表示的范围为[-2048, 2047)</li><li><strong>RISCV没有提供subi指令</strong></li></ul></li><li>问题：如何构造大数，一个32位的数<ul><li>思路：<ul><li>引入一个新的命令先设置高20位，存放在rs1</li><li>然后复用现有的addi命令补上剩余的低12位即可</li><li>[LUI指令](#LUI(Lod Upper Immediate))</li></ul></li></ul></li></ul><h3 id="基于算术运算指令实现的其他伪指令"><a href="#基于算术运算指令实现的其他伪指令" class="headerlink" title="基于算术运算指令实现的其他伪指令"></a>基于算术运算指令实现的其他伪指令</h3><table><thead><tr><th>伪指令</th><th>语法</th><th>等价指令</th><th>指令描述</th><th>例子</th></tr></thead><tbody><tr><td>neg</td><td>neg rd, rs</td><td>sub rd, x0, rs</td><td>对rs中的值取反并将结果存放在rd中</td><td>neg x5, x6</td></tr><tr><td>mv</td><td>mv rd, rs</td><td>addi rd, rs, 0</td><td>将rs中的值拷贝到rd中</td><td>mv x5, x6</td></tr><tr><td>nop</td><td>nop</td><td>addi x0, x0, 0</td><td>什么也不做</td><td>nop</td></tr></tbody></table><h3 id="LUI-Lod-Upper-Immediate"><a href="#LUI-Lod-Upper-Immediate" class="headerlink" title="LUI(Lod Upper Immediate)"></a>LUI(Lod Upper Immediate)</h3><table><thead><tr><th>语法</th><th>lui rd, imm</th><th></th></tr></thead><tbody><tr><td><strong>例子</strong></td><td>lui x5, 0x12345</td><td>x5 = 0x12345 &lt;&lt; 12</td></tr></tbody></table><ul><li><p>编码格式：<strong>U-type</strong> </p><ul><li>opcode：0b0110111</li></ul></li><li><p>lui指令构造一个32bits的立即数，这个立即数的高20位对应指令中的imm，低12位清零。这个立即数作为结果存放在rd中</p></li><li><p>利用lui+addi来为寄存器加载一个大数：</p><ul><li><p>0x12345678</p><ul><li><p>lui x1, 0x12345</p><p>addi x1, x1, 0x678</p></li></ul></li><li><p>特殊情况：0x12345FFF：0xFFF是个负数，直接用addi是错误的</p><ul><li><p>lui x1, 0x12346</p><p>addi x1, x1, -1</p></li></ul></li></ul></li></ul><h3 id="LI"><a href="#LI" class="headerlink" title="LI"></a>LI</h3><table><thead><tr><th>语法</th><th>li rd, imm</th><th></th></tr></thead><tbody><tr><td><strong>例子</strong></td><td>li x5, 0x12345789</td><td>x5 = 0x12345678</td></tr></tbody></table><ul><li>li是一个伪指令</li><li>汇编器会根据imm的实际情况自动生成正确的真实指令</li><li>用来代替lui</li></ul><h3 id="AUIPC"><a href="#AUIPC" class="headerlink" title="AUIPC"></a>AUIPC</h3><table><thead><tr><th>语法</th><th>auipc rd, imm</th><th></th></tr></thead><tbody><tr><td><strong>例子</strong></td><td>auipc x5, 0x12345</td><td>x5 = 0x12345 &lt;&lt; 12 + PC</td></tr></tbody></table><ul><li>编码格式：<strong>U-type</strong><ul><li>和lui指令类似，auipc指令构造一个32bits的立即数，这个立即数高20位对应指令中的imm，低12位清零。<strong>不同的是auipc会先将这个立即数和pc值相加，将相加的结果放入rd中</strong></li></ul></li><li>用于构造相对地址：相对PC值</li></ul><h3 id="LA-Load-Address"><a href="#LA-Load-Address" class="headerlink" title="LA(Load Address)"></a>LA(Load Address)</h3><table><thead><tr><th>语法</th><th>la rd, label</th><th></th></tr></thead><tbody><tr><td><strong>例子</strong></td><td>la x5, foo</td><td></td></tr></tbody></table><ul><li>LA是一个伪指令</li><li>具体编程时给出需要加载的label，编译器会根据实际情况利用auipc和其他指令自动生成正确的指令序列</li><li>常用于加载一个函数或变量地址</li></ul><h2 id="逻辑运算指令"><a href="#逻辑运算指令" class="headerlink" title="逻辑运算指令"></a>逻辑运算指令</h2><table><thead><tr><th>指令</th><th>格式</th><th>语法</th><th>描述</th><th>例子</th></tr></thead><tbody><tr><td>AND</td><td>R-type</td><td>AND RD, RS1, RS2</td><td>RD = RS1 &amp; RS2</td><td>and x5, x6, x7</td></tr><tr><td>OR</td><td>R-type</td><td>OR RD, RS1, RS2</td><td>RD = RS1 | RS2</td><td>or x5, x6, x7</td></tr><tr><td>XOR</td><td>R-type</td><td>XOR RD, RS1, RS2</td><td>RD = RS1 ^ RS2</td><td>xor x5, x6, x7</td></tr><tr><td>ANDI</td><td>I-type</td><td>ANDI RD, RS1, RS2</td><td>RD = RS1 &amp; IMM</td><td>andi x5, x6, 20</td></tr><tr><td>ORI</td><td>I-type</td><td>ORI RD, RS1, RS2</td><td>RD = RS1 | IMM</td><td>ori x5, x6, 20</td></tr><tr><td>XORI</td><td>I-type</td><td>XORI RD, RS1, IMM</td><td>RD = RS1 ^ IMM</td><td>xor x5, x6, 20</td></tr></tbody></table><ul><li>逻辑指令都是按位操作</li><li>xor(异或)：相同为0，相异为1</li></ul><table><thead><tr><th>伪指令</th><th>语法</th><th>等价指令</th><th>描述</th><th>例子</th></tr></thead><tbody><tr><td>NOT</td><td>NOT RD, RS</td><td>XORI RD, RS, -1</td><td>对RS的值取反，结果存在RD中</td><td>not x5, x6</td></tr></tbody></table><p>这里-1表示为16进制就是 0xFFFFFFFF，在和RS中的值异或，就达到取反的目的</p><h2 id="移位运算指令"><a href="#移位运算指令" class="headerlink" title="移位运算指令"></a>移位运算指令</h2><h3 id="逻辑移位"><a href="#逻辑移位" class="headerlink" title="逻辑移位"></a>逻辑移位</h3><table><thead><tr><th>指令</th><th>格式</th><th>语法</th><th>描述</th><th>例子</th></tr></thead><tbody><tr><td>SLL</td><td>R-type</td><td>SLL RD, RS1, RS2</td><td>逻辑左移</td><td>sll x5, x6, x7</td></tr><tr><td>SRL</td><td>R-type</td><td>SRL RD, RS1, RS2</td><td>逻辑右移</td><td>srl x5, x6, x7</td></tr><tr><td>SLLI</td><td>I-type</td><td>SRLLI RD, RS1, IMM</td><td>逻辑左移立即数</td><td>slli x5, x6, 3</td></tr><tr><td>SRLI</td><td>I-type</td><td>SRLI RD, RS1, IMM</td><td>逻辑右移立即数</td><td>srli x5, x6, 3</td></tr></tbody></table><ul><li>逻辑左移、逻辑右移都是补0</li></ul><h3 id="算术移位"><a href="#算术移位" class="headerlink" title="算术移位"></a>算术移位</h3><table><thead><tr><th>指令</th><th>格式</th><th>语法</th><th>描述</th><th>例子</th></tr></thead><tbody><tr><td>SRA</td><td>R-type</td><td>SRA RD, RS1, RS2</td><td>算术右移 RD = RS1 &gt;&gt; RS2</td><td>sra x5, x6, x7</td></tr><tr><td>SRAI</td><td>I-type</td><td>SRAI RD, RS1, IMM</td><td>算术右移立即数 RD = RS1 &gt;&gt; IMM</td><td>srai x5, x6, 3</td></tr></tbody></table><ul><li>算术右移时按照符号位值填充</li><li>算术移位只有右移，没有左移：左移会把符号位移走，就没意义了</li><li>算术移位可以作为负数除法</li></ul><h2 id="内存读写指令"><a href="#内存读写指令" class="headerlink" title="内存读写指令"></a>内存读写指令</h2><ul><li>内存读指令：Load，将数据从内存读入寄存器</li><li>内存写指令：Store，将数据从寄存器写出内存</li></ul><h3 id="内存读（Load）"><a href="#内存读（Load）" class="headerlink" title="内存读（Load）"></a>内存读（Load）</h3><table><thead><tr><th>指令</th><th>格式</th><th>语法</th><th>描述</th><th>例子</th></tr></thead><tbody><tr><td>LB</td><td>I-type</td><td>LB RD, IMM(RS1)</td><td>Load Byte，从内存中读取一个8bits的数据到RD中，内存地址 = RS1 + IMM</td><td>lb x5, 40(x6)</td></tr><tr><td>LBU</td><td>I-type</td><td>LBU RD, IMM(RS1)</td><td>Load Byte，从内存中读取一个8bit的数据到RD中</td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td></tr></tbody></table><p>//TODO</p><h1 id="exercises"><a href="#exercises" class="headerlink" title="exercises"></a>exercises</h1><h2 id="ch3-编译与链接"><a href="#ch3-编译与链接" class="headerlink" title="ch3 编译与链接"></a>ch3 编译与链接</h2><h3 id="练习3-1"><a href="#练习3-1" class="headerlink" title="练习3-1"></a>练习3-1</h3><p>使⽤ gcc 编译代码并使⽤ binutils ⼯具对⽣成的⽬标文件和可执⾏文件（ELF 格式）进⾏分析。具体要求如下： </p><ul><li><p><input checked disabled type="checkbox">  编写⼀个简单的打印 “hello world！” 的程序源文件：<code>hello.c</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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;hello world!\n&quot;</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></li><li><p><input checked disabled type="checkbox">  对源文件进⾏本地编译，⽣成针对⽀持 x86_64 指令集架构处理器的⽬标文件 <code>hello.o</code>。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc hello.c -c -o hello.o</span><br></pre></td></tr></table></figure><p>补充gcc常用选项：</p><p><code>gcc [options] [filename]</code></p><table><thead><tr><th>常用选项</th><th>含义</th></tr></thead><tbody><tr><td>-E</td><td>只做预处理</td></tr><tr><td>-c</td><td>只编译不连接，生成目标文件”.o”</td></tr><tr><td>-S</td><td>生成汇编代码</td></tr><tr><td>-o file</td><td>把输出生成到由file指定文件名的文件中</td></tr><tr><td>-g</td><td>在输出的文件中加入支持调试的信息</td></tr><tr><td>-v</td><td>显示输出详细的命令执行过程信息</td></tr></tbody></table></li><li><p><input checked disabled type="checkbox">  查看 <code>hello.o</code> 的文件的文件头信息。 </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">readelf -h hell.o</span><br></pre></td></tr></table></figure><p>信息如下：</p><figure class="highlight sql"><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></pre></td><td class="code"><pre><span class="line">ELF 头：</span><br><span class="line">  Magic：   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 </span><br><span class="line">  类别:                              ELF64</span><br><span class="line">  数据:                              2 补码，小端序 (little endian)</span><br><span class="line">  Version:                           1 (current)</span><br><span class="line">  OS/ABI:                            UNIX - System V</span><br><span class="line">  ABI 版本:                          0</span><br><span class="line">  类型:                              REL (可重定位文件)</span><br><span class="line">  系统架构:                          Advanced Micro Devices X86-64</span><br><span class="line">  版本:                              0x1</span><br><span class="line">  入口点地址：               0x0</span><br><span class="line">  程序头起点：          0 (bytes into file)</span><br><span class="line">  <span class="keyword">Start</span> <span class="keyword">of</span> <span class="keyword">section</span> headers:          <span class="number">792</span> (<span class="keyword">bytes</span> <span class="keyword">into</span> <span class="keyword">file</span>)</span><br><span class="line">  标志：             <span class="number">0x0</span></span><br><span class="line">  <span class="keyword">Size</span> <span class="keyword">of</span> this header:               <span class="number">64</span> (<span class="keyword">bytes</span>)</span><br><span class="line">  <span class="keyword">Size</span> <span class="keyword">of</span> program headers:           <span class="number">0</span> (<span class="keyword">bytes</span>)</span><br><span class="line">  <span class="built_in">Number</span> <span class="keyword">of</span> program headers:         <span class="number">0</span></span><br><span class="line">  <span class="keyword">Size</span> <span class="keyword">of</span> <span class="keyword">section</span> headers:           <span class="number">64</span> (<span class="keyword">bytes</span>)</span><br><span class="line">  <span class="built_in">Number</span> <span class="keyword">of</span> <span class="keyword">section</span> headers:         <span class="number">14</span></span><br><span class="line">  <span class="keyword">Section</span> header <span class="keyword">string</span> <span class="keyword">table</span> <span class="keyword">index</span>: <span class="number">13</span></span><br></pre></td></tr></table></figure></li></ul><ul><li><p><input checked disabled type="checkbox">  查看 <code>hello.o</code> 的 Section header table。 </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">readelf -SW hello.c</span><br></pre></td></tr></table></figure><p>信息如下：</p><figure class="highlight tap"><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">There are<span class="number"> 14 </span>section headers, starting at offset 0x318:</span><br><span class="line"></span><br><span class="line">节头：</span><br><span class="line">  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al</span><br><span class="line">  [ 0]                   NULL           <span class="number"> 0000000000000000 </span>000000<span class="number"> 000000 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 0</span><br><span class="line">  [ 1] .text             PROGBITS       <span class="number"> 0000000000000000 </span>000040 00001b<span class="number"> 00 </span> AX <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 2] .rela.text        RELA           <span class="number"> 0000000000000000 </span>000258<span class="number"> 000030 </span>18   I<span class="number"> 11 </span> <span class="number"> 1 </span> 8</span><br><span class="line">  [ 3] .data             PROGBITS       <span class="number"> 0000000000000000 </span>00005b<span class="number"> 000000 </span>00  WA <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 4] .bss              NOBITS         <span class="number"> 0000000000000000 </span>00005b<span class="number"> 000000 </span>00  WA <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 5] .rodata           PROGBITS       <span class="number"> 0000000000000000 </span>00005b 00000d<span class="number"> 00 </span>  A <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 6] .comment          PROGBITS       <span class="number"> 0000000000000000 </span>000068 00002b<span class="number"> 01 </span> MS <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 7] .note.GNU-stack   PROGBITS       <span class="number"> 0000000000000000 </span>000093<span class="number"> 000000 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 8] .note.gnu.property NOTE           <span class="number"> 0000000000000000 </span>000098<span class="number"> 000020 </span>00   A <span class="number"> 0 </span> <span class="number"> 0 </span> 8</span><br><span class="line">  [ 9] .eh_frame         PROGBITS       <span class="number"> 0000000000000000 </span>0000b8<span class="number"> 000038 </span>00   A <span class="number"> 0 </span> <span class="number"> 0 </span> 8</span><br><span class="line">  [10] .rela.eh_frame    RELA           <span class="number"> 0000000000000000 </span>000288<span class="number"> 000018 </span>18   I<span class="number"> 11 </span> <span class="number"> 9 </span> 8</span><br><span class="line">  [11] .symtab           SYMTAB         <span class="number"> 0000000000000000 </span>0000f0<span class="number"> 000138 </span>18    <span class="number"> 12 </span><span class="number"> 10 </span> 8</span><br><span class="line">  [12] .strtab           STRTAB         <span class="number"> 0000000000000000 </span>000228<span class="number"> 000029 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [13] .shstrtab         STRTAB         <span class="number"> 0000000000000000 </span>0002a0<span class="number"> 000074 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">Key to Flags:</span><br><span class="line">  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),</span><br><span class="line">  L (link order), O (extra OS processing required), G (group), T (TLS),</span><br><span class="line">  C (compressed), x (unknown), o (OS specific), E (exclude),</span><br><span class="line">  l (large), p (processor specific)</span><br></pre></td></tr></table></figure></li></ul><ul><li><p><input checked disabled type="checkbox">  对 <code>hello.o</code> 反汇编，并查看 <code>hello.c</code> 的 C 程序源码和机器指令的对应关系。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">objdump -S hello.o</span><br></pre></td></tr></table></figure><p>反汇编：</p><figure class="highlight perl"><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></pre></td><td class="code"><pre><span class="line">hello.o：     文件格式 elf64-x86-<span class="number">64</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Disassembly of section .text:</span><br><span class="line"></span><br><span class="line"><span class="number">0000000000000000</span> &lt;main&gt;:</span><br><span class="line"><span class="comment">#include &lt;stdio.h&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> main(void)</span><br><span class="line">&#123;</span><br><span class="line">   <span class="number">0</span>:   f3 0f <span class="number">1</span>e fa             endbr64 </span><br><span class="line">   <span class="number">4</span>:   <span class="number">55</span>                      <span class="keyword">push</span>   %rbp</span><br><span class="line">   <span class="number">5</span>:   <span class="number">48</span> <span class="number">89</span> e5                mov    %rsp,%rbp</span><br><span class="line">    <span class="keyword">printf</span>(<span class="string">&quot;hello world!\n&quot;</span>);</span><br><span class="line">   <span class="number">8</span>:   <span class="number">48</span> <span class="number">8</span>d <span class="number">3</span>d <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>    lea    <span class="number">0x0</span>(%rip),%rdi        <span class="comment"># f &lt;main+0xf&gt;</span></span><br><span class="line">   f:   e8 <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>          callq  <span class="number">14</span> &lt;main+<span class="number">0x14</span>&gt;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  <span class="number">14</span>:   b8 <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>          mov    $0<span class="keyword">x</span><span class="number">0</span>,%eax</span><br><span class="line">  <span class="number">19</span>:   <span class="number">5</span>d                      <span class="keyword">pop</span>    %rbp</span><br><span class="line">  <span class="number">1</span>a:   c3                      retq   </span><br></pre></td></tr></table></figure></li></ul><h3 id="练习3-2"><a href="#练习3-2" class="headerlink" title="练习3-2"></a>练习3-2</h3><p>如下例⼦ C 语⾔代码：</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><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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="keyword">int</span> global_init = <span class="number">0x11111111</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> global_const = <span class="number">0x22222222</span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">int</span> static_var = <span class="number">0x33333333</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">int</span> static_var_uninit;</span><br><span class="line">    <span class="keyword">int</span> auto_var = <span class="number">0x44444444</span>;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;hello world!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>请问编译为 .o 文件后，global_init, global_const, static_var, static_var_uninit, auto_var 这些变 量分别存放在那些 section ⾥，”hello world!\n” 这个字符串⼜在哪⾥？并尝试⽤⼯具查看并验证你的猜测。</p><ul><li><p>global_init ——-&gt; .data</p></li><li><p>global_const ——-&gt; <del>.data</del>  .rodata</p></li><li><p>static_var ——-&gt; .data</p></li><li><p>static_var_uninit ——-&gt; .bss</p></li><li><p>auto_var ——-&gt; <del>栈区</del> .text</p><p>使用<code>objdump -s -x -d test.o</code>可以得到以下信息</p><figure class="highlight css"><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="selector-tag">SYMBOL</span> <span class="selector-tag">TABLE</span>:</span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">df</span> *<span class="selector-tag">ABS</span>*  0000000000000000 <span class="selector-tag">test</span><span class="selector-class">.c</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.text</span>  0000000000000000 <span class="selector-class">.text</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.data</span>  0000000000000000 <span class="selector-class">.data</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.bss</span>   0000000000000000 <span class="selector-class">.bss</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.rodata</span>        0000000000000000 <span class="selector-class">.rodata</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>     <span class="selector-tag">O</span> <span class="selector-class">.bss</span>   0000000000000004 <span class="selector-tag">static_var_uninit</span>.2318</span><br><span class="line">0000000000000004 <span class="selector-tag">l</span>     <span class="selector-tag">O</span> <span class="selector-class">.data</span>  0000000000000004 <span class="selector-tag">static_var</span>.2317</span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.note</span><span class="selector-class">.GNU-stack</span>        0000000000000000 <span class="selector-class">.note</span><span class="selector-class">.GNU-stack</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.note</span><span class="selector-class">.gnu</span><span class="selector-class">.property</span>     0000000000000000 <span class="selector-class">.note</span><span class="selector-class">.gnu</span><span class="selector-class">.property</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.eh_frame</span>      0000000000000000 <span class="selector-class">.eh_frame</span></span><br><span class="line">0000000000000000 <span class="selector-tag">l</span>    <span class="selector-tag">d</span>  <span class="selector-class">.comment</span>       0000000000000000 <span class="selector-class">.comment</span></span><br><span class="line">0000000000000000 <span class="selector-tag">g</span>     <span class="selector-tag">O</span> <span class="selector-class">.data</span>  0000000000000004 <span class="selector-tag">global_init</span></span><br><span class="line">0000000000000000 <span class="selector-tag">g</span>     <span class="selector-tag">O</span> <span class="selector-class">.rodata</span>        0000000000000004 <span class="selector-tag">global_const</span></span><br><span class="line">0000000000000000 <span class="selector-tag">g</span>     <span class="selector-tag">F</span> <span class="selector-class">.text</span>  0000000000000022 <span class="selector-tag">main</span></span><br><span class="line">0000000000000000         *<span class="selector-tag">UND</span>*  0000000000000000 _<span class="selector-tag">GLOBAL_OFFSET_TABLE_</span></span><br><span class="line">0000000000000000         *<span class="selector-tag">UND</span>*  0000000000000000 <span class="selector-tag">puts</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="ch4-嵌入式开发介绍"><a href="#ch4-嵌入式开发介绍" class="headerlink" title="ch4 嵌入式开发介绍"></a>ch4 嵌入式开发介绍</h2><h3 id="练习4-1"><a href="#练习4-1" class="headerlink" title="练习4-1"></a>练习4-1</h3><p>熟悉交叉编译概念，使⽤ riscv gcc 编译代码并使⽤ binutils ⼯具对⽣成的⽬标文件和可执⾏文件（ELF 格式） 进⾏分析。具体要求如下： </p><ul><li><p><input checked disabled type="checkbox">  编写⼀个简单的打印”hello world!”的程序源文件<code>hello.c</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><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;hello world!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p><input checked disabled type="checkbox">  对源文件进⾏编译，⽣成针对⽀持 rv32ima 指令集架构处理器的⽬标文件<code>hello.o</code>。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">riscv64-unknown-elf-gcc -march=rv32ima -mabi=ilp32 -c hello.c</span><br></pre></td></tr></table></figure><blockquote><p>2022-08-13补充:</p><p>Ubuntu20.04系统直接apt install搭建的环境，编译这个练习会报错:</p><p>编译命令:</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/bin/riscv64-unknown-elf-gcc <span class="attribute">-march</span>=rv32ima <span class="attribute">-mabi</span>=ilp32 -c hello.c </span><br></pre></td></tr></table></figure><p>报错：</p><figure class="highlight shell"><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">hello.c:1:10: fatal error: stdio.h: No such file or directory</span><br><span class="line">    1 | #include &lt;stdio.h&gt;</span><br><span class="line">      |          ^~~~~~~~~</span><br><span class="line">compilation terminated.</span><br></pre></td></tr></table></figure><p>根据仓库[issue](<a href="https://gitee.com/unicornx/riscv-operating-system-mooc/issues/I4D6N9">stdio.h 头文件找不到 · Issue #I4D6N9 · unicornx/riscv-operating-system-mooc - Gitee.com</a>)可以知道这是工具链的问题，解决方法很简单，根据[howto-run-with-ubuntu1804_zh.md](<a href="https://gitee.com/unicornx/riscv-operating-system-mooc/blob/main/howto-run-with-ubuntu1804_zh.md">howto-run-with-ubuntu1804_zh.md · unicornx/riscv-operating-system-mooc - 码云 - 开源中国 (gitee.com)</a>)搭建环境即可，这个应该是不挑Ubuntu版本的，我在Ubuntu20.04上已经没问题</p></blockquote></li><li><p><input checked disabled type="checkbox">  查看<code>hello.o</code>的文件的文件头信息。 </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">readelf -h hello.o</span><br></pre></td></tr></table></figure><p>信息如下：</p><figure class="highlight sql"><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></pre></td><td class="code"><pre><span class="line">ELF 头：</span><br><span class="line">  Magic：   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 </span><br><span class="line">  类别:                              ELF32</span><br><span class="line">  数据:                              2 补码，小端序 (little endian)</span><br><span class="line">  Version:                           1 (current)</span><br><span class="line">  OS/ABI:                            UNIX - System V</span><br><span class="line">  ABI 版本:                          0</span><br><span class="line">  类型:                              REL (可重定位文件)</span><br><span class="line">  系统架构:                          RISC-V</span><br><span class="line">  版本:                              0x1</span><br><span class="line">  入口点地址：               0x0</span><br><span class="line">  程序头起点：          0 (bytes into file)</span><br><span class="line">  <span class="keyword">Start</span> <span class="keyword">of</span> <span class="keyword">section</span> headers:          <span class="number">556</span> (<span class="keyword">bytes</span> <span class="keyword">into</span> <span class="keyword">file</span>)</span><br><span class="line">  标志：             <span class="number">0x0</span></span><br><span class="line">  <span class="keyword">Size</span> <span class="keyword">of</span> this header:               <span class="number">52</span> (<span class="keyword">bytes</span>)</span><br><span class="line">  <span class="keyword">Size</span> <span class="keyword">of</span> program headers:           <span class="number">0</span> (<span class="keyword">bytes</span>)</span><br><span class="line">  <span class="built_in">Number</span> <span class="keyword">of</span> program headers:         <span class="number">0</span></span><br><span class="line">  <span class="keyword">Size</span> <span class="keyword">of</span> <span class="keyword">section</span> headers:           <span class="number">40</span> (<span class="keyword">bytes</span>)</span><br><span class="line">  <span class="built_in">Number</span> <span class="keyword">of</span> <span class="keyword">section</span> headers:         <span class="number">11</span></span><br><span class="line">  <span class="keyword">Section</span> header <span class="keyword">string</span> <span class="keyword">table</span> <span class="keyword">index</span>: <span class="number">10</span></span><br></pre></td></tr></table></figure></li></ul><ul><li><p><input checked disabled type="checkbox">  查看 <code>hello.o</code> 的 Section header table。 </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">readelf -S hello.o</span><br></pre></td></tr></table></figure><p>信息如下：</p><figure class="highlight tap"><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></pre></td><td class="code"><pre><span class="line">There are<span class="number"> 11 </span>section headers, starting at offset 0x22c:</span><br><span class="line"></span><br><span class="line">节头：</span><br><span class="line">  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al</span><br><span class="line">  [ 0]                   NULL           <span class="number"> 00000000 </span>000000<span class="number"> 000000 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 0</span><br><span class="line">  [ 1] .text             PROGBITS       <span class="number"> 00000000 </span>000034<span class="number"> 000038 </span>00  AX <span class="number"> 0 </span> <span class="number"> 0 </span> 4</span><br><span class="line">  [ 2] .rela.text        RELA           <span class="number"> 00000000 </span>000190<span class="number"> 000048 </span>0c   I <span class="number"> 8 </span> <span class="number"> 1 </span> 4</span><br><span class="line">  [ 3] .data             PROGBITS       <span class="number"> 00000000 </span>00006c<span class="number"> 000000 </span>00  WA <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 4] .bss              NOBITS         <span class="number"> 00000000 </span>00006c<span class="number"> 000000 </span>00  WA <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 5] .rodata           PROGBITS       <span class="number"> 00000000 </span>00006c 00000d<span class="number"> 00 </span>  A <span class="number"> 0 </span> <span class="number"> 0 </span> 4</span><br><span class="line">  [ 6] .comment          PROGBITS       <span class="number"> 00000000 </span>000079<span class="number"> 000029 </span>01  MS <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 7] .riscv.attributes RISCV_ATTRIBUTE<span class="number"> 00000000 </span>0000a2<span class="number"> 000026 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [ 8] .symtab           SYMTAB         <span class="number"> 00000000 </span>0000c8 0000b0<span class="number"> 10 </span>    <span class="number"> 9 </span> <span class="number"> 9 </span> 4</span><br><span class="line">  [ 9] .strtab           STRTAB         <span class="number"> 00000000 </span>000178<span class="number"> 000018 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">  [10] .shstrtab         STRTAB         <span class="number"> 00000000 </span>0001d8<span class="number"> 000054 </span>00     <span class="number"> 0 </span> <span class="number"> 0 </span> 1</span><br><span class="line">Key to Flags:</span><br><span class="line">  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),</span><br><span class="line">  L (link order), O (extra OS processing required), G (group), T (TLS),</span><br><span class="line">  C (compressed), x (unknown), o (OS specific), E (exclude),</span><br><span class="line">  p (processor specific)</span><br></pre></td></tr></table></figure></li></ul><ul><li><p><input checked disabled type="checkbox">  对<code>hello.o</code> 反汇编，并查看 hello.c 的 C 程序源码和机器指令的对应关系。</p><p><strong>注意：</strong>直接使用<code>objdump</code>不行，因为不支持riscv架构。</p><blockquote><p>2022-08-13补充:</p><p>提示如下:</p><figure class="highlight vhdl"><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">hello.o：     文件格式 elf32-little</span><br><span class="line">objdump: can<span class="symbol">&#x27;t</span> disassemble <span class="keyword">for</span> <span class="keyword">architecture</span> UNKNOWN!</span><br></pre></td></tr></table></figure></blockquote><p>所以使用以下命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">riscv64-unknown-elf-objdump -S hello.o</span><br></pre></td></tr></table></figure><p>信息如下：</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">hello.o：     文件格式 elf32-littleriscv</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Disassembly of section .text:</span><br><span class="line"></span><br><span class="line">00000000 &lt;main&gt;:</span><br><span class="line">   0:   ff010113                addi    sp,sp,-16</span><br><span class="line">   4:   00112623                sw      ra,12(sp)</span><br><span class="line">   8:   00812423                sw      s0,8(sp)</span><br><span class="line">   c:   01010413                addi    s0,sp,16</span><br><span class="line">  10:   000007b7                lui     a5,0x0</span><br><span class="line">  14:   00078513                mv      a0,a5</span><br><span class="line">  18:   00000097                auipc   ra,0x0</span><br><span class="line">  1c:   000080e7                jalr    ra # 18 &lt;main+0x18&gt;</span><br><span class="line">  20:   00000793                li      a5,0</span><br><span class="line">  24:   00078513                mv      a0,a5</span><br><span class="line">  28:   00c12083                lw      ra,12(sp)</span><br><span class="line">  2c:   00812403                lw      s0,8(sp)</span><br><span class="line">  30:   01010113                addi    sp,sp,16</span><br><span class="line">  34:   00008067                ret</span><br></pre></td></tr></table></figure></li></ul><h3 id="练习4-2"><a href="#练习4-2" class="headerlink" title="练习4-2"></a>练习4-2</h3><p>基于 练习 4-1 继续熟悉 qemu/gdb 等⼯具的使⽤，具体要求如下：</p><ul><li><p><input checked disabled type="checkbox">  将 <code>hello.c</code> 编译成可调式版本的可执⾏程序 <code>a.out</code> </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">riscv64-unknown-elf-gcc -g -march=rv32ima -mabi=ilp32  hello.c</span><br></pre></td></tr></table></figure></li><li><p><input checked disabled type="checkbox">  先执⾏ <code>qemu-riscv32</code> 运⾏ <code>a.out</code>。 </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">qemu-riscv32 ./a.out</span><br></pre></td></tr></table></figure><p>可以看到控制台输出以下内容：</p><figure class="highlight erlang-repl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hello world!</span><br></pre></td></tr></table></figure></li><li><p><input checked disabled type="checkbox">  使⽤ <code>qemu-riscv32</code> 和 gdb 调试 <code>a.out</code>。</p><p>这里会用到两个终端，一个终端打开qemu并同时监听1234端口；一个终端打开gdb，连接1234端口，步骤如下：</p><ul><li><p>在终端1，使用<code>qemu-riscv32 -g 1234 a.out</code></p></li><li><p>这时在终端2，使用<code>riscv64-unknown-elf-gdb</code>直接进入gdb(不要使用默认的gdb，不支持rv32)</p><ul><li>随后在gdb中使用<code>set architecture riscv:rv32</code>设置架构</li><li>然后设置断点(因为只有<code>hello world</code>一行代码)，<code>b hello.c:5</code></li><li>最后使用<code>target remote localhost:1234</code>连接qemu</li></ul></li><li><p>这时终端2会显示</p><figure class="highlight shell"><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">Remote debugging using localhost:1234</span><br><span class="line">warning: No executable has been specified and target does not support</span><br><span class="line">determining executable automatically.  Try using the &quot;file&quot; command.</span><br><span class="line">0x00010090 in ?? ()</span><br></pre></td></tr></table></figure><p>这是因为我们设置了断点，想运行的话按<code>r</code>或者<code>c</code></p></li><li><p>最后在终端一可以看到<code>hello world!</code></p></li></ul><p><img src="/2022/01/27/%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0%E5%BC%80%E5%8F%91RISCV-OS/image-20220813191251160.png" alt="image-20220813191251160"></p></li></ul><h3 id="练习4-3"><a href="#练习4-3" class="headerlink" title="练习4-3"></a>练习4-3</h3><ul><li><p><input checked disabled type="checkbox">  ⾃学 Makefile 的语法，理解在 riscv-operating-system-mooc 仓库的根⽬录下执⾏ make 会发⽣什么。</p><p><a href="https://ethereal14.github.io/2022/01/26/Makefile%E5%AD%A6%E4%B9%A0/">Makefile学习</a></p></li></ul><h2 id="ch5-RISC-V汇编语言编程"><a href="#ch5-RISC-V汇编语言编程" class="headerlink" title="ch5 RISC-V汇编语言编程"></a>ch5 RISC-V汇编语言编程</h2><h3 id="练习5-1"><a href="#练习5-1" class="headerlink" title="练习5-1"></a>练习5-1</h3><ul><li><p><input checked disabled type="checkbox">  对 code/asm/sub 执⾏反汇编，查看 sub x5, x6, x7 这条汇编指令对应的机器指令的编码，并对照 RISC-V 的 specificaion ⾃⼰解析该条指令的编码。 </p><ul><li><p>使用<code>make hex</code>可查看二进制编码</p><figure class="highlight bash"><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">00000000  13 03 f0 ff 93 03 e0 ff  b3 02 73 40 6f 00 00 00  |..........s@o...|</span><br><span class="line">00000010</span><br></pre></td></tr></table></figure><p>由于指令是<strong>四字节</strong>对齐的，所以可以知道<code>b3 02 73 40</code>是<code>sub x5,x6,x7</code>对应的16进制编码，并且是小端序，所以可以分析出该指令值为<code>0x407302b3</code>，同时可以使用<code>make code</code>进行求证</p></li><li><p>针对<code>0x407302b3</code>可以先转成二进制：<code>01000000-01110011-00000010-10110011</code></p><p><img src="/2022/01/27/%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0%E5%BC%80%E5%8F%91RISCV-OS/image-20220820223553230.png" alt="image-20220820223553230"></p><p>该图可知，指令的低7位可以确定指令类型，该指令低7位：0110011，分析得出该指令属于<code>OP</code>，<code>R-Type</code>类型</p></li><li><p>接下来可以查看<code>funct3</code>与<code>funct7</code>，<code>funct3</code>在12<del>14位，<code>funct7</code>在25</del>31位</p><p>可以得到<code>funct3</code>为000，<code>funct7</code>为0100000</p><p><img src="/2022/01/27/%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0%E5%BC%80%E5%8F%91RISCV-OS/image-20220820225734713.png" alt="image-20220820225734713"></p></li><li><p>opcode、funct3、funct7可以确定指令了</p><p><img src="/2022/01/27/%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0%E5%BC%80%E5%8F%91RISCV-OS/image-20220820225828577.png" alt="image-20220820225828577"></p></li><li><p>寄存器由上图可知：rd为7<del>11，rs1为15</del>18，rs2为20~24，分析可知：rd=00101→x5；rs1=00110→x6；rs2=00111→x7</p></li></ul></li><li><p><input checked disabled type="checkbox">  现知道某条 RISC-V 的机器指令在内存中的值为 b3 05 95 00，从左往右为从低地址到⾼地址，单位为 字节，请将其翻译为对应的汇编指令。</p><ul><li><p>该值化为易读形式：0x009505b3，再化为二进制：00000000-10010101-00000101-10110011</p></li><li><p>首先分析opcode：0110011，为<code>OP</code>，<code>R-Type</code>类型</p></li><li><p>然后分析funct3、funct7：分别为000,0000000，结合opcode，分析得出该指令为<code>add</code>指令</p></li><li><p>随后分析寄存器：rd=01011→x11，rs1=01010→x10，rs2=01001→x9</p></li><li><p>最后该指令为：<code>add x11,x10,x9</code></p></li><li><p>可以写代码验证：</p><p><img src="/2022/01/27/%E5%BE%AA%E5%BA%8F%E6%B8%90%E8%BF%9B%E5%AD%A6%E4%B9%A0%E5%BC%80%E5%8F%91RISCV-OS/image-20220820232154908.png" alt="image-20220820232154908"></p></li></ul></li></ul><h3 id="练习5-2"><a href="#练习5-2" class="headerlink" title="练习5-2"></a>练习5-2</h3><p>假设有如下这么一段C语言程序代码，尝试写一段汇编代码，达到等效的结果，并采用gdb调试查看执行结果，注意请使用寄存器来存放变量的值：</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="keyword">register</span> <span class="keyword">int</span> a, b, c, d, e;</span><br><span class="line">b = <span class="number">1</span>;</span><br><span class="line">c = <span class="number">2</span>;</span><br><span class="line">e = <span class="number">3</span>;</span><br><span class="line">a = b + c;</span><br><span class="line">d = a - e;</span><br></pre></td></tr></table></figure><ul><li><p>首先定义变量使用了<code>register</code>，意为将变量保存在寄存器中，和“注意”里边的相照应</p></li><li><p>汇编代码：</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">    .text</span><br><span class="line">    .global _start</span><br><span class="line"></span><br><span class="line">_start:</span><br><span class="line">    li x5, 1        # b &#x3D; 1</span><br><span class="line">    li x6, 2        # c &#x3D; 2</span><br><span class="line">    li x7, 3        # e &#x3D; 3</span><br><span class="line">    add x9, x5, x6  # x9 &#x3D; x5 + x6  # a &#x3D; b + c</span><br><span class="line">    sub x10, x9, x7</span><br><span class="line">    </span><br><span class="line">stop:</span><br><span class="line">    j stop</span><br><span class="line"></span><br><span class="line">    .end</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>直接<code>make &amp;&amp; make debug</code>就可以得到如下结果（gdbinit中display了x5到x11寄存器）</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">stop () at test.s:19</span><br><span class="line">19          j stop</span><br><span class="line">=&gt; 0x80000014 &lt;stop+0&gt;: 6f 00 00 00     j       0x80000014 &lt;stop&gt;</span><br><span class="line">1: /z $x5 = 0x00000001</span><br><span class="line">2: /z $x6 = 0x00000002</span><br><span class="line">3: /z $x7 = 0x00000003</span><br><span class="line">4: /z $x9 = 0x00000003</span><br><span class="line">5: /z $x10 = 0x00000000</span><br><span class="line">6: /z $x11 = 0x87e00000</span><br></pre></td></tr></table></figure></li></ul><h3 id="练习5-3"><a href="#练习5-3" class="headerlink" title="练习5-3"></a>练习5-3</h3><p>假设有如下这么一段C语言程序代码，尝试写一段汇编代码，达到等效的结果，并采用gdb调试查看执行结果，注意请使用寄存器来存放变量的值：</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="keyword">register</span> <span class="keyword">int</span> a, b, c, d, e;</span><br><span class="line">b = <span class="number">1</span>;</span><br><span class="line">c = <span class="number">2</span>;</span><br><span class="line">d = <span class="number">3</span>;</span><br><span class="line">e = <span class="number">4</span>;</span><br><span class="line">a = (b + c) - (d + e);</span><br></pre></td></tr></table></figure><ul><li><p>本练习和<a href="#%E7%BB%83%E4%B9%A05-2">练习5-2</a>差不多，不过是运算稍复杂</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">    .text</span><br><span class="line">    .global _start</span><br><span class="line"></span><br><span class="line">_start:</span><br><span class="line">    li x1, 1        # b &#x3D; 1</span><br><span class="line">    li x2, 2        # c &#x3D; 2</span><br><span class="line">    li x3, 3        # d &#x3D; 3</span><br><span class="line">    li x4, 4        # e &#x3D; 4</span><br><span class="line">    add x1, x1, x2</span><br><span class="line">    add x3, x3, x4</span><br><span class="line">    sub x5, x1, x3</span><br><span class="line"></span><br><span class="line">stop:</span><br><span class="line">    j stop</span><br><span class="line"></span><br><span class="line">    .end</span><br></pre></td></tr></table></figure></li><li><p>不过上述代码最后输出结果如下，x5为<code>0xfffffffc</code>，x5为-4，而负数在计算机中使用补码表示，可以计算一下它的原码：减一然后按位取反</p><ul><li>减一：<code>0xfffffffb</code>，二进制：<code>1111 1111 1111 1111 1111 1111 1111 1011</code></li><li>取反：<code>0x00000004</code>，二进制：<code>0000 0000 0000 0000 0000 0000 0000 0100</code></li></ul><figure class="highlight shell"><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">Breakpoint 1, stop () at test.s:23</span><br><span class="line">23          j stop</span><br><span class="line">=&gt; 0x8000001c &lt;stop+0&gt;: 6f 00 00 00     j       0x8000001c &lt;stop&gt;</span><br><span class="line">1: /z $x1 = 0x00000003</span><br><span class="line">2: /z $x2 = 0x00000002</span><br><span class="line">3: /z $x3 = 0x00000007</span><br><span class="line">4: /z $x4 = 0x00000004</span><br><span class="line">5: /z $x5 = 0xfffffffc</span><br><span class="line">6: /z $x6 = 0x00000000</span><br><span class="line">7: /z $x7 = 0x00000000</span><br><span class="line">(gdb) </span><br></pre></td></tr></table></figure></li></ul><h3 id="练习5-4"><a href="#练习5-4" class="headerlink" title="练习5-4"></a>练习5-4</h3><p>给定一个32位数<code>0x87654321</code>，先编写c程序，将其低16位(<code>0x4321</code>)和高16位(<code>0x8765</code>)分别分离出来保存到独立变量中；完成后在尝试采用汇编语言实现类似效果</p><blockquote><p>通过逻辑左右移就可以了</p></blockquote><ul><li><p>C语言</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">foo</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">int</span> i = <span class="number">0x87654321</span>;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">int</span> high = i &gt;&gt; <span class="number">16</span>;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">int</span> low = (i &lt;&lt; <span class="number">16</span>)&gt;&gt;<span class="number">16</span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;i    = 0x%x\n&quot;</span></span><br><span class="line">           <span class="string">&quot;high = 0x%x\n&quot;</span></span><br><span class="line">           <span class="string">&quot;low  = 0x%x\n&quot;</span>, i, high, low);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    foo();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>RISC-V汇编</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line"># exercise 5-4</span><br><span class="line"></span><br><span class="line">    .text</span><br><span class="line">    .global _start</span><br><span class="line"></span><br><span class="line">_start:</span><br><span class="line">    li x1, 0x87654321</span><br><span class="line">    srli x2, x1, 16</span><br><span class="line">    slli x3, x1, 16</span><br><span class="line">    srli x3, x3, 16</span><br><span class="line">    </span><br><span class="line">stop:</span><br><span class="line">    j stop</span><br><span class="line"></span><br><span class="line">    .end</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ul><h3 id="练习7-1"><a href="#练习7-1" class="headerlink" title="练习7-1"></a>练习7-1</h3><p>要求：完全采用汇编语言重写01-helloRVOS, 运行后在控制台打印输出”Hello, RVOS!”</p><ul><li><strong>字符数组这儿，即代码中的<code>.data</code>后边的内容放在目前位置没问题，先前放在<code>_start</code>前边就G了，具体原因待排查</strong></li></ul><figure class="highlight plain"><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br></pre></td><td class="code"><pre><span class="line">#include &quot;platform.h&quot;</span><br><span class="line">.data</span><br><span class="line">    array:</span><br><span class="line">        .byte &#39;H&#39;, &#39;e&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;, &#39;,&#39;, &#39;R&#39;, &#39;V&#39;, &#39;O&#39;, &#39;S&#39;, &#39;!&#39;, 0</span><br><span class="line">        .space 12</span><br><span class="line">    # size of each hart&#39;s stack is 1024 bytes</span><br><span class="line">    .equ    STACK_SIZE, 1024</span><br><span class="line">    .global _start</span><br><span class="line"></span><br><span class="line">    .text</span><br><span class="line"></span><br><span class="line">    .macro uart_read_reg reg1, reg2</span><br><span class="line">        lb \reg1, 0(\reg2)</span><br><span class="line">    .endm</span><br><span class="line"></span><br><span class="line">    .macro uart_write_reg reg1, v</span><br><span class="line">        sb \v, 0(\reg1)</span><br><span class="line">    .endm</span><br><span class="line"></span><br><span class="line">_start:</span><br><span class="line">    csrr t0, mhartid    # 读Hart id</span><br><span class="line">    mv tp, t0</span><br><span class="line">    bnez   t0, park</span><br><span class="line"></span><br><span class="line">    slli t0, t0, 10     #t0 向左移动10位, 1024</span><br><span class="line">    la sp, stacks + STACK_SIZE</span><br><span class="line"></span><br><span class="line">    add sp, sp, t0; #  把sp移动到Hart对应的栈的栈顶位置上</span><br><span class="line"></span><br><span class="line">    li s0, 0x10000000</span><br><span class="line"></span><br><span class="line">    j start_kernel</span><br><span class="line">    </span><br><span class="line"></span><br><span class="line">park:</span><br><span class="line">    wfi</span><br><span class="line">    j park</span><br><span class="line"></span><br><span class="line">stacks:</span><br><span class="line">    .skip STACK_SIZE * MAXNUM_CPU</span><br><span class="line"></span><br><span class="line">start_kernel:</span><br><span class="line">    # prologue</span><br><span class="line">    addi sp, sp, -8; # sp &#x3D; sp + -8</span><br><span class="line">    sw ra, 0(sp) # </span><br><span class="line"></span><br><span class="line">    call uart_init</span><br><span class="line"></span><br><span class="line">    la a0, array</span><br><span class="line"></span><br><span class="line">    call uart_puts</span><br><span class="line"></span><br><span class="line">uart_init:</span><br><span class="line">    addi sp, sp, -20</span><br><span class="line"></span><br><span class="line">    addi s1, s0, 0x01</span><br><span class="line">    uart_write_reg s1, zero # uart_write_reg(IER, 0x00);</span><br><span class="line">                            # sb \v, 0(\reg1)</span><br><span class="line"></span><br><span class="line">    addi s1, s0, 0x03            # uint8_t lcr &#x3D; uart_read_reg(LCR);</span><br><span class="line">    uart_read_reg s2, s1    # lb \reg1, 0(\reg2)</span><br><span class="line"></span><br><span class="line">    slli s2, s2, 7          # uart_write_reg(LCR, lcr | (1 &lt;&lt; 7));</span><br><span class="line">    uart_write_reg s1, s2   </span><br><span class="line"></span><br><span class="line">    li s2, 0x03             # uart_write_reg(DLL, 0x03);</span><br><span class="line">    uart_write_reg s0, s2 </span><br><span class="line"></span><br><span class="line">    addi s1, s0, 0x01       # uart_write_reg(DLM, 0x00);</span><br><span class="line">    li s2, 0x00</span><br><span class="line">    uart_write_reg s1, s2</span><br><span class="line">    </span><br><span class="line">    addi s1, s0, 0x03       # uart_write_reg(LCR, lcr | (3 &lt;&lt; 0));</span><br><span class="line">    li s2, 0x03</span><br><span class="line">    uart_write_reg s1, s2</span><br><span class="line"></span><br><span class="line">    addi sp, sp, 20</span><br><span class="line">    ret</span><br><span class="line"></span><br><span class="line">uart_puts:</span><br><span class="line">    addi sp, sp, -12; # sp &#x3D; sp + -12</span><br><span class="line">    sw s1, 0(sp)</span><br><span class="line">    sw s2, 4(sp)</span><br><span class="line">    sw ra, 8(sp)</span><br><span class="line"></span><br><span class="line">    mv s1, a0</span><br><span class="line">loop:</span><br><span class="line">    lbu a0, 0(s1)</span><br><span class="line">    mv s2, a0</span><br><span class="line">    addi s1, s1, 1; # a0 &#x3D; a0 + 1</span><br><span class="line">    jal uart_putc  # jump to uart_puts and save position to ra</span><br><span class="line">    bnez s2, loop</span><br><span class="line"></span><br><span class="line">    lw s1, 0(sp) # </span><br><span class="line">    lw s2, 4(sp) # </span><br><span class="line">    lw ra, 8(sp) # </span><br><span class="line">    addi sp, sp, 12; # sp &#x3D; sp + 12</span><br><span class="line">    ret</span><br><span class="line"></span><br><span class="line">uart_putc:</span><br><span class="line">    addi sp, sp, -8; # sp &#x3D; sp + -8</span><br><span class="line">    sw s1, 0(sp)</span><br><span class="line">    sw s2, 4(sp) # </span><br><span class="line">    </span><br><span class="line">    addi s1, s0, 5; # s1 &#x3D; s0 + 5</span><br><span class="line">    uart_read_reg s2, s1</span><br><span class="line">check:</span><br><span class="line">    andi s2, s2, 32; # s2 &#x3D; s2 &amp; 32</span><br><span class="line">    beqz s2, check</span><br><span class="line"></span><br><span class="line">    uart_write_reg s0, a0 </span><br><span class="line"></span><br><span class="line">    lw s1, 0(sp) # </span><br><span class="line">    lw s2, 4(sp) # </span><br><span class="line">    addi sp, sp, 8; # sp &#x3D; sp + 8</span><br><span class="line">    ret</span><br><span class="line"></span><br><span class="line">    .end</span><br></pre></td></tr></table></figure><h3 id="练习7-2"><a href="#练习7-2" class="headerlink" title="练习7-2"></a>练习7-2</h3><p>要求：参考01-helloRVOS，在此基础上采用轮询方式读取控制台上输入的字符并回显在控制台上。另外用户按下回车后能够另起一行从头开始</p><blockquote><p>为节省篇幅，只记录修改部分</p></blockquote><ul><li>纯单片机编辑，读写寄存器就完事。</li></ul><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* kernel.c */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;types.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;platform.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">extern</span> <span class="keyword">void</span> <span class="title">uart_init</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">extern</span> <span class="keyword">void</span> <span class="title">uart_puts</span><span class="params">(<span class="keyword">char</span> *s)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">extern</span> <span class="keyword">int</span> <span class="title">uart_putc</span><span class="params">(<span class="keyword">char</span> ch)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">extern</span> <span class="keyword">char</span> <span class="title">uart_getc</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">start_kernel</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    uart_init();</span><br><span class="line">    uart_puts(<span class="string">&quot;hello, RVOS!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">uint8_t</span> ch = uart_getc();</span><br><span class="line">        <span class="keyword">if</span> (ch == <span class="string">&#x27;\r&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            uart_puts(<span class="string">&quot;\r\n&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        uart_putc(ch);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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="comment">/* uart.c */</span></span><br><span class="line"><span class="function"><span class="keyword">char</span> <span class="title">uart_getc</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span> ((uart_read_reg(LSR) &amp; LSR_RX_READY) == <span class="number">0</span>)&#123;&#125;</span><br><span class="line">    <span class="keyword">return</span> uart_read_reg(RHR);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">练习与笔记</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
  </entry>
  
  <entry>
    <title>Makefile学习</title>
    <link href="https://ethereal14.github.io/2022/01/26/Makefile%E5%AD%A6%E4%B9%A0/"/>
    <id>https://ethereal14.github.io/2022/01/26/Makefile%E5%AD%A6%E4%B9%A0/</id>
    <published>2022-01-26T15:49:30.000Z</published>
    <updated>2023-03-12T16:03:10.149Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Makefile规则"><a href="#Makefile规则" class="headerlink" title="Makefile规则"></a>Makefile规则</h1><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line"><span class="section">target:prerequisites #目标:依赖的文件或者其他目标</span></span><br><span class="line">cmd_1</span><br><span class="line">cmd_2</span><br><span class="line">cmd_3</span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>:clean#伪目标</span></span><br><span class="line"><span class="section">clean:</span></span><br><span class="line">cmd</span><br></pre></td></tr></table></figure><h1 id="Makefile变量、模式匹配"><a href="#Makefile变量、模式匹配" class="headerlink" title="Makefile变量、模式匹配"></a>Makefile变量、模式匹配</h1><h3 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h3><ul><li><p>系统变量</p><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>: all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(CC)</span>&quot;</span> </span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(AS)</span>&quot;</span> </span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(MAKE)</span>&quot;</span> </span><br><span class="line"><span class="comment">#输出结果</span></span><br><span class="line"><span class="comment">#echo &quot;cc&quot; </span></span><br><span class="line"><span class="comment">#cc</span></span><br><span class="line"><span class="comment">#echo &quot;as&quot; </span></span><br><span class="line"><span class="comment">#as</span></span><br><span class="line"><span class="comment">#echo &quot;make&quot; </span></span><br><span class="line"><span class="comment">#make</span></span><br></pre></td></tr></table></figure></li></ul><ul><li><p>自定义变量</p><ul><li><p>=，延迟赋值（引用此变量的时候才赋值）</p><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line">A=123</span><br><span class="line">B=<span class="variable">$(A)</span></span><br><span class="line">A=456</span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>: all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(B)</span>&quot;</span> </span><br><span class="line"><span class="comment">#输出结果</span></span><br><span class="line"><span class="comment">#456</span></span><br></pre></td></tr></table></figure></li></ul></li></ul><ul><li><p>:=，立即赋值</p><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line">A=123</span><br><span class="line">B:=<span class="variable">$(A)</span></span><br><span class="line">A=456</span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>: all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(B)</span>&quot;</span> </span><br><span class="line"><span class="comment">#输出结果</span></span><br><span class="line"><span class="comment">#123</span></span><br></pre></td></tr></table></figure></li><li><p>?=，空赋值（变量为空的时候才有效）</p><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line">A?=123</span><br><span class="line"><span class="comment">#B:=$(A)</span></span><br><span class="line">A?=456</span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>: all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(A)</span>&quot;</span> </span><br><span class="line"><span class="comment">#输出结果</span></span><br><span class="line"><span class="comment">#123</span></span><br></pre></td></tr></table></figure></li><li><p>+=，追加赋值（不会改变变量的值）</p><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line">A?=123</span><br><span class="line"><span class="comment">#B:=$(A)</span></span><br><span class="line">A+=456</span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>: all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(A)</span>&quot;</span> </span><br><span class="line"><span class="comment">#输出结果</span></span><br><span class="line"><span class="comment">#123 456</span></span><br></pre></td></tr></table></figure></li></ul><ul><li><p>自动化变量</p><ul><li><p>$&lt;，第一个依赖文件</p></li><li><p>$^，全部的依赖文件</p></li><li><p>$@，目标</p><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line"><span class="section">all:targeta targetb</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$&lt;</span>&quot;</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$^</span>&quot;</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$@</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="section">targeta:</span></span><br><span class="line"></span><br><span class="line"><span class="section">targetb:</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#输出结果</span></span><br><span class="line"><span class="comment">#echo &quot;targeta&quot;</span></span><br><span class="line"><span class="comment">#targeta</span></span><br><span class="line"><span class="comment">#echo &quot;targeta targetb&quot;</span></span><br><span class="line"><span class="comment">#targeta targetb</span></span><br><span class="line"><span class="comment">#echo &quot;all&quot;</span></span><br><span class="line"><span class="comment">#all</span></span><br></pre></td></tr></table></figure></li></ul></li></ul><h3 id="模式匹配"><a href="#模式匹配" class="headerlink" title="模式匹配"></a>模式匹配</h3><p>%，匹配任意多个非空字符</p><p>类似于shell的*通配符</p><figure class="highlight makefile"><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="section">%:</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$@</span>&quot;</span></span><br></pre></td></tr></table></figure><h4 id="默认规则"><a href="#默认规则" class="headerlink" title="默认规则"></a>默认规则</h4><p>.o文件默认使用.c文件编译</p><h1 id="Makefile条件分支"><a href="#Makefile条件分支" class="headerlink" title="Makefile条件分支"></a>Makefile条件分支</h1><figure class="highlight makefile"><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="keyword">ifeq</span>(var1,var2)</span><br><span class="line">....</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">....</span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure><figure class="highlight makefile"><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="keyword">ifneq</span>(var1,var2)</span><br><span class="line">....</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">....</span><br><span class="line"><span class="keyword">endif</span></span><br></pre></td></tr></table></figure><h1 id="Makefile常用函数"><a href="#Makefile常用函数" class="headerlink" title="Makefile常用函数"></a>Makefile常用函数</h1><h4 id="patsubst"><a href="#patsubst" class="headerlink" title="patsubst"></a>patsubst</h4><p>模式替换函数</p><figure class="highlight makefile"><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="meta"><span class="meta-keyword">.PHONY</span>:all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;$(patsubst %.c,%.o,x.c.c bar.c)&quot;</span></span><br></pre></td></tr></table></figure><p>把字串“x.c.c bar.c”中以.c 结尾的单词替换成以.o 结尾的字符。函数的返回结果 是“x.c.o bar.o”</p><h4 id="notdir"><a href="#notdir" class="headerlink" title="notdir"></a>notdir</h4><p>取文件名函数</p><figure class="highlight makefile"><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="meta"><span class="meta-keyword">.PHONY</span>:all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;$(notdir src/foo.c hacks)&quot;</span></span><br></pre></td></tr></table></figure><p>返回值为：“foo.c hacks”</p><h4 id="wildcard"><a href="#wildcard" class="headerlink" title="wildcard"></a>wildcard</h4><p>获取匹配模式文件名函数</p><figure class="highlight makefile"><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="meta"><span class="meta-keyword">.PHONY</span>:all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;$(wildcard *.c)&quot;</span></span><br></pre></td></tr></table></figure><p>返回值为当前目录下所有.c 源文件列表</p><h4 id="foreach"><a href="#foreach" class="headerlink" title="foreach"></a>foreach</h4><p>函数“foreach”不同于其它函数。它是一个循环函数。类似于 Linux 的 shell 中的 for 语句</p><figure class="highlight makefile"><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">dirs := a b c d </span><br><span class="line">files := <span class="variable">$(<span class="built_in">foreach</span> <span class="built_in">dir</span>,<span class="variable">$(dirs)</span>,$(<span class="built_in">wildcard</span> <span class="variable">$(dir)</span>/*)</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>:all</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">echo <span class="string">&quot;<span class="variable">$(files)</span>&quot;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>把文件夹里边的文件全部找出来</p><h1 id="Makefile解决头文件依赖"><a href="#Makefile解决头文件依赖" class="headerlink" title="Makefile解决头文件依赖"></a>Makefile解决头文件依赖</h1><ol><li>写一个头文件，并把头文件添加到编译器的头文件的路径    </li><li>实时检查头文件的更新情况，一旦头文件发生变化，应该重新编译所有相关文件</li></ol><h1 id="较为完善的Makefile"><a href="#较为完善的Makefile" class="headerlink" title="较为完善的Makefile"></a>较为完善的Makefile</h1><figure class="highlight makefile"><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></pre></td><td class="code"><pre><span class="line">ARCH?=x86</span><br><span class="line"><span class="keyword">ifeq</span> (<span class="variable">$(ARCH)</span>,x86)</span><br><span class="line">CC=gcc</span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">CC=arm-linux-gnueabihf-gcc</span><br><span class="line"><span class="keyword">endif</span></span><br><span class="line"></span><br><span class="line">TARGET=mp3</span><br><span class="line">BUILD_DIR=build</span><br><span class="line">SRC_DIR=module1 module2</span><br><span class="line">INC_DIR=<span class="keyword">include</span></span><br><span class="line">CFLAGS=<span class="variable">$(<span class="built_in">patsubst</span> %,-I%,<span class="variable">$(INC_DIR)</span>)</span></span><br><span class="line"></span><br><span class="line">INCLUDE= <span class="variable">$(<span class="built_in">foreach</span> <span class="built_in">dir</span>,<span class="variable">$(INC_DIR)</span>,$(<span class="built_in">wildcard</span> <span class="variable">$(dir)</span>/*.h)</span>)</span><br><span class="line">SOURCES=  <span class="variable">$(<span class="built_in">foreach</span> <span class="built_in">dir</span>,<span class="variable">$(SRC_DIR)</span>,$(<span class="built_in">wildcard</span> <span class="variable">$(dir)</span>/*.c)</span>)</span><br><span class="line">OBJS=<span class="variable">$(<span class="built_in">patsubst</span> %.c,<span class="variable">$(BUILD_DIR)</span>/%.o,$(<span class="built_in">notdir</span> <span class="variable">$(SOURCES)</span>)</span>)</span><br><span class="line">VPATH=<span class="variable">$(SRC_DIR)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable">$(BUILD_DIR)</span>/<span class="variable">$(TARGET)</span>:<span class="variable">$(OBJS)</span></span><br><span class="line"><span class="variable">$(CC)</span> <span class="variable">$^</span> -o <span class="variable">$@</span> <span class="variable">$(CFLAGS)</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$(BUILD_DIR)</span>/%.o:%.c <span class="variable">$(INCLUDE)</span> | create_build</span><br><span class="line"><span class="variable">$(CC)</span> -c <span class="variable">$&lt;</span> -o <span class="variable">$@</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>:create_build</span></span><br><span class="line"><span class="section">create_build:</span></span><br><span class="line">mkdir -p <span class="variable">$(BUILD_DIR)</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>:clean</span></span><br><span class="line"><span class="section">clean:</span></span><br><span class="line">rm -rf <span class="variable">$(BUILD_DIR)</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">快速了解一下Makefile，为了RVOS课程</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="Makefile" scheme="https://ethereal14.github.io/tags/Makefile/"/>
    
  </entry>
  
  <entry>
    <title>牛客Linux服务器开发</title>
    <link href="https://ethereal14.github.io/2021/12/29/%E7%89%9B%E5%AE%A2Linux%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BC%80%E5%8F%91/"/>
    <id>https://ethereal14.github.io/2021/12/29/%E7%89%9B%E5%AE%A2Linux%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BC%80%E5%8F%91/</id>
    <published>2021-12-29T12:06:54.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    
    
    
    <category term="视频笔记" scheme="https://ethereal14.github.io/categories/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Linux网络编程" scheme="https://ethereal14.github.io/tags/Linux%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>select、poll、epoll的使用</title>
    <link href="https://ethereal14.github.io/2021/09/16/select%E3%80%81poll%E3%80%81epoll%E7%9A%84%E4%BD%BF%E7%94%A8/"/>
    <id>https://ethereal14.github.io/2021/09/16/select%E3%80%81poll%E3%80%81epoll%E7%9A%84%E4%BD%BF%E7%94%A8/</id>
    <published>2021-09-16T12:59:56.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    <content type="html"><![CDATA[<h4 id="select系统调用"><a href="#select系统调用" class="headerlink" title="select系统调用"></a>select系统调用</h4><p>select系统调用的用途是：在一段时间内，监听多个文件描述符上的可读、可写和异常等事件。</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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/time.h&gt;         /* For portability */ </span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/select.h&gt; </span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">select</span><span class="params">(<span class="keyword">int</span> nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)</span></span>;</span><br></pre></td></tr></table></figure><ul><li>nfds 被监听文件描述符的总和(readfds + writefds + exceptfds)</li><li>readfds、writefds、exceptfds分别指向可读、可写、异常事件对应的文件描述符集合</li><li>timeout 超时时间<ul><li><pre><code>      ==0，检查一遍文件描述符状态立即返回；</code></pre></li><li>== NULL 或者 非零值，会一直阻塞直到：<ul><li><pre><code>                         三种fds中有至少一个文件描述符进入ready状态</code></pre></li><li><pre><code>                       被信号处理中断</code></pre></li><li><pre><code>                       到达指定的超时时间</code></pre></li></ul></li></ul></li></ul>]]></content>
    
    
    <summary type="html">Linux下三种I/O多路复用的学习</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="Linux 网络编程" scheme="https://ethereal14.github.io/tags/Linux-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>黑马C++网络编程</title>
    <link href="https://ethereal14.github.io/2021/06/10/heimacpp-netprogram/"/>
    <id>https://ethereal14.github.io/2021/06/10/heimacpp-netprogram/</id>
    <published>2021-06-10T13:14:09.000Z</published>
    <updated>2023-03-12T16:03:10.201Z</updated>
    
    <content type="html"><![CDATA[<h1 id="OSI七层模型-TCP-IP模型"><a href="#OSI七层模型-TCP-IP模型" class="headerlink" title="OSI七层模型-TCP/IP模型"></a>OSI七层模型-TCP/IP模型</h1><p><img src="/2021/06/10/heimacpp-netprogram/image-20210610212135741.png" alt="image-20210610212135741"></p><h1 id="各个层级协议"><a href="#各个层级协议" class="headerlink" title="各个层级协议"></a>各个层级协议</h1><table><thead><tr><th>层级</th><th>协议</th></tr></thead><tbody><tr><td>应用层</td><td>http、ftp、nfs、ssh、telnet</td></tr><tr><td>传输层</td><td>tcp、udp</td></tr><tr><td>网络层</td><td>IP、ICMP、IGMP</td></tr><tr><td>链路层</td><td>以太网帧协议、ARP</td></tr></tbody></table><h1 id="C-S、B-S模型优缺点"><a href="#C-S、B-S模型优缺点" class="headerlink" title="C/S、B/S模型优缺点"></a>C/S、B/S模型优缺点</h1><table><thead><tr><th></th><th>C/S</th><th>B/S</th></tr></thead><tbody><tr><td>优点</td><td>缓存大量数据、协议选择灵活、速度快</td><td>安全性较高、跨平台、开发工作量小</td></tr><tr><td>缺点</td><td>开发工作量较大、安全性、不能跨平台</td><td>不能缓存大量数据、阉割遵守http协议</td></tr></tbody></table><h1 id="网络传输流程"><a href="#网络传输流程" class="headerlink" title="网络传输流程"></a>网络传输流程</h1><p>数据没有封装之前，是不能在网络中传递</p><p>数据-应用层-传输层-网络层-链路层   网络环境</p><h1 id="协议简介"><a href="#协议简介" class="headerlink" title="协议简介"></a>协议简介</h1><ul><li><p>以太网帧协议</p><ul><li>ARP：根据IP地址获取mac地址</li><li>以太网帧协议：根据MAC地址，完成数据包传输</li></ul></li><li><p>IP协议</p><ul><li><p>版本：IPv4、IPv6</p></li><li><p>TTL</p><ul><li>time to live </li><li>设置数据包在路由节点中的跳转上限。每经过一个路由  节点，该值-1，减为0的路由有义务将该数据包丢弃</li></ul></li><li><p>源IP：32位 — 4字节 192.168.1.108—点分十进制</p></li><li><p>目的IP：32位—-4字节</p><p>IP地址可以在网络环境中唯一标识一台主机</p><p>端口号：可以在网络的一台主机上，唯一的标识一个进程</p><p>IP地址+端口号：唯一标识一个进程</p></li></ul></li><li><p>UDP</p><ul><li>16位源端口号</li><li>16位目的端口号</li></ul></li><li><p>TCP</p><ul><li>16位源端口号</li><li>16位目的端口号</li><li>32位序号</li><li>32确认序号</li><li>6个标志位</li><li>16位窗口大小 2^16=65536</li></ul></li></ul><h1 id="网络套接字"><a href="#网络套接字" class="headerlink" title="网络套接字"></a>网络套接字</h1><ul><li><p>小端法(本地字节序)</p><ul><li><p>高位高地址、低位低地址                    </p></li><li><p>int a = 0x12345678</p><ul><li><img src="/2021/06/10/heimacpp-netprogram/image-20210610213342655.png" alt="image-20210610213342655" style="zoom:25%;"></li></ul></li></ul></li></ul><ul><li><p>大端法(网络字节序)</p><ul><li>高位低地址、低位高地址</li></ul></li><li><p>htonl –&gt; 本地 –&gt; 网络(IP)</p></li><li><p>htons –&gt; 本地 –&gt; 网络(port)</p></li><li><p>ntohl     –&gt; 网络(IP)     –&gt; 本地</p></li><li><p>ntohs     –&gt; 网络(port)     –&gt; 本地</p></li></ul><h1 id="IP地址转换"><a href="#IP地址转换" class="headerlink" title="IP地址转换"></a>IP地址转换</h1><ul><li><p>int inet_pton(int af, const     char *src, void *dst);</p><ul><li>本地字节序转换为网络字节序</li><li>af：AF_INET、AF_INET6</li><li>src：IP地址(点分十进制)</li><li>dst：传出：转换后的网络字节序 IP地址</li><li>返回值：<ul><li>成功返回 1</li><li>异常返回 0，说明src指向的不是一个有效的ip地址</li><li>失败返回 -1 </li></ul></li></ul></li><li><ul><li></li></ul></li><li><p>const char     *inet_ntop(int af, const void *src,char *dst, socklen_t size);</p><ul><li><p>本地字节序转换为网络字节序</p></li><li><p>af：AF_INET、AF_INET6</p></li><li><p>src：网络字节序IP地址</p></li><li><p>dst：本地字节序</p></li><li><p>size：dst的大小</p></li><li><p>返回值：</p><ul><li>成功返回 dst</li><li>失败返回 NULL</li></ul></li></ul></li></ul><h1 id="sockaddr地址结构"><a href="#sockaddr地址结构" class="headerlink" title="sockaddr地址结构"></a>sockaddr地址结构</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><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">addr</span>；</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">addr</span>.<span class="title">sin_family</span> =</span> AF_INET;</span><br><span class="line"></span><br><span class="line">addr.sin_port = htons(<span class="number">8080</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> dst;</span><br><span class="line"></span><br><span class="line">inet_pton(AF_INET,<span class="string">&quot;127.0.0.1&quot;</span>,(<span class="keyword">void</span> *)&amp;dst);</span><br><span class="line"></span><br><span class="line">addr.sin_addr.s_addr = dst;</span><br><span class="line"></span><br><span class="line">addr.sin_addr.s_addr = htonl(INADDR_ANY);</span><br><span class="line"></span><br><span class="line">bind(fd,(struct sockaddr*)&amp;addr,size);</span><br></pre></td></tr></table></figure><h1 id="socket模型穿件流程图"><a href="#socket模型穿件流程图" class="headerlink" title="socket模型穿件流程图"></a>socket模型穿件流程图</h1><img src="/2021/06/10/heimacpp-netprogram/image-20210610213819187.png" alt="image-20210610213819187" style="zoom:80%;"><p><strong>一个服务端和一个客户端建立通信一共三个套接字</strong></p><h2 id="服务端、客户端"><a href="#服务端、客户端" class="headerlink" title="服务端、客户端"></a>服务端、客户端</h2><ul><li><p>服务端：</p><ul><li>bind()绑定ip+port</li></ul></li></ul><pre><code>- listen()设置同时监听上限- accept()阻塞监听客户端连接</code></pre><ul><li>客户端：<ul><li>connect()绑定ip+port</li></ul></li></ul><h1 id="套接字函数"><a href="#套接字函数" class="headerlink" title="套接字函数"></a>套接字函数</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">socket</span><span class="params">(<span class="keyword">int</span> domain, <span class="keyword">int</span> type, <span class="keyword">int</span> protocol)</span></span>; </span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">*创建一个套接字</span></span><br><span class="line"><span class="comment">*domain: AF_INET、AF_INET6、AF_UNIX</span></span><br><span class="line"><span class="comment">*type：SOCK_STREAM、SOCK_DGRAM</span></span><br><span class="line"><span class="comment">*protocol：0</span></span><br><span class="line"><span class="comment">*返回值：</span></span><br><span class="line"><span class="comment">*成功：新套接字所对应的文件描述符</span></span><br><span class="line"><span class="comment">*失败：-1 errno</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">bind</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">const</span> struct sockaddr *addr,<span class="keyword">socklen_t</span> addrlen)</span></span>;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">*给socket绑定一个地址结构</span></span><br><span class="line"><span class="comment">*sockfd：socket函数返回值</span></span><br><span class="line"><span class="comment">*struct sockaddr_in addr;</span></span><br><span class="line"><span class="comment">*addr.sin_family = AF_INET;</span></span><br><span class="line"><span class="comment">*addr.sin_port = htons(8888);</span></span><br><span class="line"><span class="comment">*addr.sin_addr.s_addr = htonl(INADDR_ANY);</span></span><br><span class="line"><span class="comment">*addr：传入参数(struct sockaddr*)&amp;address</span></span><br><span class="line"><span class="comment">*addrlen:sizeof(addr) 地址结构的大小</span></span><br><span class="line"><span class="comment">*返回值：</span></span><br><span class="line"><span class="comment">*成功：0</span></span><br><span class="line"><span class="comment">*失败：-1 error</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">listen</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">int</span> backlog)</span></span>; </span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">*设置同时与服务器建立连接的上线数(同时进行3次握手 的客服端数量)</span></span><br><span class="line"><span class="comment">*sockfd：socket函数返回值</span></span><br><span class="line"><span class="comment">*backlog：上限的值</span></span><br><span class="line"><span class="comment">*返回值：</span></span><br><span class="line"><span class="comment">*成功：0</span></span><br><span class="line"><span class="comment">*失败： -1 error</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">accept</span><span class="params">(<span class="keyword">int</span> sockfd, struct sockaddr *addr, <span class="keyword">socklen_t</span> *addrlen)</span></span>;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">*阻塞等待客服端建立连接，成功返回一个与客户端成功连接的socket文件描述符</span></span><br><span class="line"><span class="comment">*sockfd：socket函数返回值</span></span><br><span class="line"><span class="comment">*addr：传出参数。成功与服务器建立连接的那个客服端的地址结构</span></span><br><span class="line"><span class="comment">*addrlen：&amp;client_addr_len。传入传出。入：addr的大小，出：客服端addr的实际大小</span></span><br><span class="line"><span class="comment">*socket_t client_addr_len = sizeof(addr);</span></span><br><span class="line"><span class="comment">*返回值：</span></span><br><span class="line"><span class="comment">*成功：能与服务器进行数据通信的socket对应的文件描述符</span></span><br><span class="line"><span class="comment">*失败：-1 error</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">connect</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">const</span> struct sockaddr *addr, <span class="keyword">socklen_t</span> addrlen)</span></span>;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">*使用现有socket与服务器建立连接</span></span><br><span class="line"><span class="comment">*sockfd：socket函数返回值</span></span><br><span class="line"><span class="comment">*addr：传入参数。服务器的地址结构(struct sockaddr*)&amp;address</span></span><br><span class="line"><span class="comment">*addrlen：sizeof(addr) 服务器地址结构的大小</span></span><br><span class="line"><span class="comment">*返回值：</span></span><br><span class="line"><span class="comment">*成功：0</span></span><br><span class="line"><span class="comment">*失败： -1 error</span></span><br><span class="line"><span class="comment">* 如果不使用bind()函数绑定客户端地质结构，采用&quot;隐式绑定&quot;。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="TCP通信流程分析"><a href="#TCP通信流程分析" class="headerlink" title="TCP通信流程分析"></a>TCP通信流程分析</h1><table><thead><tr><th>server</th><th></th><th>client</th><th></th></tr></thead><tbody><tr><td>socket()</td><td>创建socket</td><td>socket()</td><td>创建socket</td></tr><tr><td>bind()</td><td>绑定服务器地址结构</td><td>connect()</td><td>与服务器建立连接</td></tr><tr><td>listen()</td><td>设置监听上限</td><td>write()</td><td>写数据到socket</td></tr><tr><td>accept()</td><td>阻塞监听客户端连接</td><td>read()</td><td>读数据</td></tr><tr><td>read()</td><td>读socket获取客户端数据</td><td>close()</td><td></td></tr><tr><td>write()</td><td>写数据</td><td></td><td></td></tr><tr><td>close()</td><td>关闭套接字</td><td></td><td></td></tr></tbody></table><h1 id="TCP协议"><a href="#TCP协议" class="headerlink" title="TCP协议"></a>TCP协议</h1><ul><li><p>三次握手</p><ul><li>主动发起连接请求端，发送 SYN 标志位，请求建立连接。携带数据包包号、数据字节数(0)、滑动窗口大小。</li><li>被动接受连接请求端，发送 ACK 标志位，同时携带 SYN 请求标志位。携带序号、确认序号、数据字节数(0)、滑动窗口大小。</li><li>主动发起连接请求端，发送 ACK 标志位，应答服务器连接请求。携带序号、确认序号</li></ul></li><li><p><img src="/2021/06/10/heimacpp-netprogram/image-20210613142506250.png" alt="image-20210613142506250"></p></li><li><p>四次挥手</p><ul><li>主动关闭连接请求端，发送 FIN 标志位。</li><li>被动关闭连接请求端，应答 ACK 标志位。 —–半关闭完成</li><li>被动关闭连接请求端，发送 FIN 标志位。</li><li>主动关闭连接请求端，应答 ACK 标志位 。——连接全部关闭</li></ul></li></ul><p><img src="/2021/06/10/heimacpp-netprogram/image-20210613152316871.png" alt="image-20210613152316871"></p><ul><li>滑动窗口<ul><li>发送给连接对端，本段缓冲区实时大小，保证数据不会丢失</li></ul></li></ul><h1 id="TCP状态时序图"><a href="#TCP状态时序图" class="headerlink" title="TCP状态时序图"></a>TCP状态时序图</h1><p><img src="/2021/06/10/heimacpp-netprogram/image-20210629165910770.png" alt="image-20210629165910770"></p><ol><li><p>主动发起连接请求端：CLOSE — 发送SYN — SYN_SEND — 接收ACK、SYN — SYN_SEND — 发送方ACK — ESTABLISHED(数据通信状态)</p></li><li><p>主动关闭连接请求端：ESTABLISHED(数据通信状态) — 发送FIN — FIN_WAIT_1—  接收ACK —  FIN_WAIT_2 —  接收对端发送的FIN — FIN_WAIT_2 — 回发ACK — TIME_WAIT(只有主动关闭连接方，会经历该状态) —  等2MSL时长 — CLOSED</p></li><li><p>被动接收连接请求端：CLOSE — LISTEN — 接收SYN — LISTEN — 发送ACK、SYN — SYN_RCVD — 接收ACK — ESTABLISHED</p></li><li><p>被动关闭连接请求端：ESTABLISHED—接收对端FIN — ESTABLISHED — 发送ACK — CLOSE_WAIT(说明对端(主动关闭连接端)处于半关闭状态) — 发送FIN — LAST_ACK — 接收ACK — CLOSE</p></li></ol><p><em>重点记忆： ESTABLISHED、FIN_WAIT_2 、CLOSE_WAIT、TIME_WAIT(2MSL时长)</em></p><h2 id="2MSL时长"><a href="#2MSL时长" class="headerlink" title="2MSL时长"></a>2MSL时长</h2><p><strong><em>一定出现在主动关闭连接请求一端</em></strong></p><p><strong>保证，最后一个ACK能被成功接收。(等待期间，对端没有接收到ACK，对端会再次发送FIN请求)</strong></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><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> opt = <span class="number">1</span>; <span class="comment">//设置端口复用</span></span><br><span class="line">setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,(<span class="keyword">void</span> *)&amp;opt,<span class="keyword">sizeof</span>(opt));</span><br></pre></td></tr></table></figure><h2 id="半关闭"><a href="#半关闭" class="headerlink" title="半关闭"></a>半关闭</h2><p><em>通信双方只有一端关闭通信。——FIN_WAIT_2(半关闭状态)</em></p><p><code>close(cfd);</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">shutdown</span><span class="params">(itn fd, <span class="keyword">int</span> how)</span></span></span><br><span class="line"><span class="function"><span class="comment">/**    how:SHUT_RD 关闭读</span></span></span><br><span class="line"><span class="function"><span class="comment"> *       SHUT_WR关闭写</span></span></span><br><span class="line"><span class="function"><span class="comment"> *       SHUT_RDWR关闭读写</span></span></span><br><span class="line"><span class="function"><span class="comment">**/</span></span></span><br></pre></td></tr></table></figure><p><strong>区别：</strong></p><ul><li>shutdown在关闭多个文件描述符应用的文件时，采用全关闭的方法，close只关闭一个</li></ul><h1 id="错误处理函数"><a href="#错误处理函数" class="headerlink" title="错误处理函数"></a>错误处理函数</h1><p><strong>封装目的</strong></p><ul><li>在server.c编程过程中突出裸机，将出错处理与逻辑分开，可以直接跳转man手册</li></ul><p><strong>wrap.c</strong></p><ul><li>存放网络信相关常用　自定义函数</li><li>命名方式：<ul><li>系统调用函数首字母大写 方便查看man手册。如：Listen()、Accept()</li></ul></li><li>函数功能：调用系统调用函数，处理出错场景</li><li>在server.c 和 client.c 中调用 自定义函数<ul><li>server.c 和 wrap.c 生成 server</li><li>client.c 和 wrap.c 生成 client</li></ul></li></ul><p><strong>wrap.h</strong></p><ul><li>存放 网络通信相关常用 自定义函数原神(声明)</li></ul><h1 id="高并发服务器"><a href="#高并发服务器" class="headerlink" title="高并发服务器"></a>高并发服务器</h1><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><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></pre></td><td class="code"><pre><span class="line">Socket();<span class="comment">//创建监听套接字 lfd</span></span><br><span class="line">Bind();<span class="comment">//绑定地址结构 </span></span><br><span class="line">Listen();<span class="comment">//设置监听上限</span></span><br><span class="line"><span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">&#123;</span><br><span class="line">    cfd = Accpet();<span class="comment">//接收客户端连接请求</span></span><br><span class="line">    pid = fork();<span class="comment">//</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span>(pid == <span class="number">0</span>)<span class="comment">//子进程read()--&gt;小写转大写--&gt;write(cfd)</span></span><br><span class="line">    &#123;</span><br><span class="line">        close(lfd);<span class="comment">//关闭用于建立连接的套接字</span></span><br><span class="line">        read();</span><br><span class="line">        upper();</span><br><span class="line">        write();</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        close(cfd);<span class="comment">//关闭用于与客户端通信的套接字 cfd</span></span><br><span class="line"></span><br><span class="line">        contiue;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>子进程</p><ul><li> close(lfd);        //关闭用于建立连接的套接字</li><li>read();    </li><li>upper();</li><li> write();</li></ul></li><li><p>父进程</p><ul><li><p>注册信号捕捉函数：SIGCHLD</p></li><li><p>在回调函数中，完成子进程回收</p><p>  ​        while ( waitpid());</p></li></ul></li></ul><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><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></pre></td><td class="code"><pre><span class="line">Socket();<span class="comment">//创建监听套接字 lfd</span></span><br><span class="line">Bind();<span class="comment">//绑定地址结构 </span></span><br><span class="line">Listen();<span class="comment">//设置监听上限</span></span><br><span class="line"><span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">&#123;</span><br><span class="line">    cfd = Accpet();<span class="comment">//接收客户端连接请求</span></span><br><span class="line">    pthread_create(&amp;tid, <span class="literal">NULL</span>,tfn,<span class="literal">NULL</span>);</span><br><span class="line">    pthread_detach(tid);</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="function"><span class="keyword">void</span> *<span class="title">tfn</span><span class="params">(<span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    close(lfd);</span><br><span class="line">read(cfd);</span><br><span class="line">    upper();</span><br><span class="line">    write(cfd);</span><br><span class="line">    pthread_exit((<span class="keyword">void</span>*)<span class="number">10</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="read函数返回值"><a href="#read函数返回值" class="headerlink" title="read函数返回值"></a>read函数返回值</h2><ol><li>大于0   实际读到的字节数</li><li>等于0   已经读到结尾(对端已经关闭)【重点】</li><li>-1         应该进一步判断errno的值<ol><li>errno= EAGAIN or EWOULDBLOCK：设置了非阻塞方式读。没有数据到达</li><li>errno= EINTR 慢速系统调用被 中断</li><li>errno= “其他情况” 异常。</li></ol></li></ol><h2 id="select多路IO转接"><a href="#select多路IO转接" class="headerlink" title="select多路IO转接"></a>select多路IO转接</h2><ul><li>原理：借助内核，select来监听，客户端连接、数据通            信事件</li></ul><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 清空一个文件描述符集合</span></span><br><span class="line"><span class="comment"> * fd_set rset;</span></span><br><span class="line"><span class="comment"> * FD_ZERO(&amp;rset);</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">FD_ZERO</span><span class="params">(fd_set *<span class="built_in">set</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 将监听的文件描述符，添加到集合中</span></span><br><span class="line"><span class="comment"> * FD_SET(3,&amp;rset);FD_SET(4,&amp;rset);FD_SET(5,&amp;rset);</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">FD_SET</span><span class="params">(<span class="keyword">int</span> fd,fd_set*<span class="built_in">set</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 将一个文件描述符从监听集合中删除</span></span><br><span class="line"><span class="comment">* FD_CLR(4,&amp;rset);</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">FD_CLR</span><span class="params">(<span class="keyword">int</span> fd,fd_set *<span class="built_in">set</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 判断一个文件描述符是否在监听集合中</span></span><br><span class="line"><span class="comment"> * FD_ISSET(4,&amp;rset);</span></span><br><span class="line"><span class="comment"> * 返回值：在：1；不在：0;</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">FD_ISSET</span><span class="params">(<span class="keyword">int</span> fd,fd_set *<span class="built_in">set</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 判断一个文件描述符是否在监听集合中</span></span><br><span class="line"><span class="comment"> * nfds: 监听的所有文件描述符中，最大文件描述符+1</span></span><br><span class="line"><span class="comment"> * readfds:读  文件描述符监听集合  传入传出参数</span></span><br><span class="line"><span class="comment"> * writefds: 写  文件描述符监听集合传入传出参数NULL</span></span><br><span class="line"><span class="comment"> * exceptfds: 异常  文件描述符监听集合传入传出参数NULL</span></span><br><span class="line"><span class="comment"> * timeout:&gt;0: 设置监听超时时长</span></span><br><span class="line"><span class="comment"> NULL: 阻塞监听</span></span><br><span class="line"><span class="comment"> 0:非阻塞监听,轮询</span></span><br><span class="line"><span class="comment"> * 返回值:</span></span><br><span class="line"><span class="comment"> &gt;0:所有监听 集合中，满足对应事件的总数。</span></span><br><span class="line"><span class="comment">  0:没有满足监听条件的文件描述符</span></span><br><span class="line"><span class="comment"> -1:errno</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">select</span><span class="params">(<span class="keyword">int</span> nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout)</span></span>;</span><br></pre></td></tr></table></figure><p><strong><em>思路分析：</em></strong></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><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></pre></td><td class="code"><pre><span class="line">lfd = socket();  <span class="comment">//创建套接字</span></span><br><span class="line">bind();<span class="comment">//绑定地址结构</span></span><br><span class="line">listen();<span class="comment">//设置监听上限</span></span><br><span class="line"></span><br><span class="line">fd_set rset,allset;<span class="comment">//创建r监听集合</span></span><br><span class="line">FD_ZERO(&amp;allset);<span class="comment">//将监听r集合清空</span></span><br><span class="line">FD_SET(lfd,&amp;allset);<span class="comment">//将lfd添加至读集合中</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">&#123;</span><br><span class="line">    rset = allset;<span class="comment">//保存监听集合</span></span><br><span class="line">    ret = select(lfd+<span class="number">1</span>,&amp;rset,<span class="literal">NULL</span>,<span class="literal">NULL</span>,<span class="literal">NULL</span>); <span class="comment">//监听文件描述符集合对应事件</span></span><br><span class="line">    <span class="keyword">if</span>(ret&gt;<span class="number">0</span>)&#123;<span class="comment">//有监听的描述符满足对应事件</span></span><br><span class="line">        <span class="keyword">if</span>(FD_ISSET(lfd,&amp;rset))</span><br><span class="line">        &#123;</span><br><span class="line">            cfd = accept();<span class="comment">//建立连接，返回用于通信的文件描述符</span></span><br><span class="line">            FD_SET(cfd,&amp;allset);<span class="comment">//添加到监听通信描述符集合中</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span>(i=lfd+<span class="number">1</span>;i&lt;=最大文件描述符;i++)</span><br><span class="line">        &#123;</span><br><span class="line">            FD_ISSET(i,&amp;rset);</span><br><span class="line">            read();</span><br><span class="line">            小---大</span><br><span class="line">            write();</span><br><span class="line">        &#125;</span><br><span class="line">&#125;   </span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">黑马的网络编程</summary>
    
    
    
    <category term="视频笔记" scheme="https://ethereal14.github.io/categories/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Linux网络编程" scheme="https://ethereal14.github.io/tags/Linux%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>RT-Thread_Mqtt_Modbus线下培训</title>
    <link href="https://ethereal14.github.io/2021/06/07/RT-Thread-Mqtt-Modbus%E7%BA%BF%E4%B8%8B%E5%9F%B9%E8%AE%AD/"/>
    <id>https://ethereal14.github.io/2021/06/07/RT-Thread-Mqtt-Modbus%E7%BA%BF%E4%B8%8B%E5%9F%B9%E8%AE%AD/</id>
    <published>2021-06-07T12:48:49.000Z</published>
    <updated>2023-03-12T16:03:10.149Z</updated>
    
    <content type="html"><![CDATA[<p>先鸽一段时间</p>]]></content>
    
    
    <summary type="html">去了RTT组织的线下培训，信息量是真的好大。回来好好记录一下。</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="RT-Thread" scheme="https://ethereal14.github.io/tags/RT-Thread/"/>
    
  </entry>
  
  <entry>
    <title>线程池实现-C++版本</title>
    <link href="https://ethereal14.github.io/2021/06/07/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AE%9E%E7%8E%B0-C-%E7%89%88%E6%9C%AC/"/>
    <id>https://ethereal14.github.io/2021/06/07/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AE%9E%E7%8E%B0-C-%E7%89%88%E6%9C%AC/</id>
    <published>2021-06-07T12:12:03.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    <content type="html"><![CDATA[<h1 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h1><p>C++版本的线程池是根据C语言版本修改来的，为了熟悉一下C++的相关语法，所以就有了这篇笔记。记录一下修改的过程中遇到的问题。</p><p>本线程池是<strong>基于对象</strong>的，并不是<strong>面向对象</strong>。</p><p>[线程池简单实现(基于C语言)](<a href="https://ethereal14.github.io/2021/04/11/Linux-C%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0/">Linux C线程池简单实现 | Blog (ethereal14.github.io)</a>)</p><ul><li><input disabled type="checkbox"> 也不知道会不会有内存泄露的问题，这些事以后再说</li></ul><h1 id="文件说明"><a href="#文件说明" class="headerlink" title="文件说明"></a>文件说明</h1><table><thead><tr><th>文件名</th><th>作用</th></tr></thead><tbody><tr><td>threadpool.cpp</td><td>线程池成员函数具体实现</td></tr><tr><td>threadpool.h</td><td>线程池对象的定义、各种枚举类型</td></tr><tr><td>main.cpp</td><td>测试用例</td></tr><tr><td>CMakeLists.txt</td><td>使用cmake组织的工程</td></tr></tbody></table><h1 id="线程池对象设计"><a href="#线程池对象设计" class="headerlink" title="线程池对象设计"></a>线程池对象设计</h1><p>基本就是把原来的结构体改成现在的class，把变量定义在private里。把工作线程定义为静态成员函数</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><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">threadpool</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="keyword">pthread_mutex_t</span> m_lock;</span><br><span class="line">    <span class="keyword">pthread_cond_t</span> m_notify;</span><br><span class="line">    <span class="keyword">pthread_t</span> *m_threads;</span><br><span class="line">    threadpool_task *m_queue;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> m_thread_count;</span><br><span class="line">    <span class="keyword">int</span> m_queue_size;</span><br><span class="line">    <span class="keyword">int</span> m_head;</span><br><span class="line">    <span class="keyword">int</span> m_tail;</span><br><span class="line">    <span class="keyword">int</span> m_count;</span><br><span class="line">    <span class="keyword">int</span> m_shutdown;</span><br><span class="line">    <span class="keyword">int</span> m_started;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> *<span class="title">threadpool_thread</span><span class="params">(<span class="keyword">void</span> *arg)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    threadpool(<span class="keyword">int</span> thread_count, <span class="keyword">int</span> queue_size, <span class="keyword">int</span> flags);</span><br><span class="line">    ~threadpool();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">threadpool_add</span><span class="params">(threadpool *pool, <span class="keyword">void</span> (*function)(<span class="keyword">void</span> *), <span class="keyword">void</span> *argument, <span class="keyword">int</span> flag)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">threadpoolexit</span><span class="params">(threadpool *pool, <span class="keyword">int</span> flag)</span></span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="任务队列对象"><a href="#任务队列对象" class="headerlink" title="任务队列对象"></a>任务队列对象</h1><p>如上，仅仅把struct改为class</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><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">threadpool_task</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">void</span> (*function)(<span class="keyword">void</span> *);</span><br><span class="line">    <span class="keyword">void</span> *argument;</span><br><span class="line">    threadpool_task();</span><br><span class="line">    ~threadpool_task();</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="各种枚举类型"><a href="#各种枚举类型" class="headerlink" title="各种枚举类型"></a>各种枚举类型</h1><ul><li><input disabled type="checkbox"> 不知道能不能把这些枚举类型放在class里边，以后有空研究</li></ul><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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">enum</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    threadpool_invalid = <span class="number">-1</span>,</span><br><span class="line">    threadpool_lock_failure = <span class="number">-2</span>,</span><br><span class="line">    threadpool_queue_full = <span class="number">-3</span>,</span><br><span class="line">    threadpool_shutdown = <span class="number">-4</span>,</span><br><span class="line">    threadpool_thread_failure = <span class="number">-5</span></span><br><span class="line">&#125; <span class="keyword">threadpool_terror_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">enum</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    immediate_shutdown = <span class="number">1</span>, <span class="comment">//自动关闭</span></span><br><span class="line">    graceful_shutdown = <span class="number">2</span>   <span class="comment">//立即关闭</span></span><br><span class="line">&#125; <span class="keyword">threadpool_shutdown_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">enum</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    threadpool_graceful = <span class="number">1</span></span><br><span class="line">&#125; <span class="keyword">threadpool_destroy_flags_t</span>;</span><br></pre></td></tr></table></figure><h1 id="线程池构造函数"><a href="#线程池构造函数" class="headerlink" title="线程池构造函数"></a>线程池构造函数</h1><ul><li>这里遇到个问题：构造函数是没有返回值的，所以不能把原来的创建线程池函数照搬过来。<ul><li>使用do while结构来进行构造</li></ul></li></ul><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><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">threadpool::threadpool(<span class="keyword">int</span> thread_count = <span class="number">32</span>, <span class="keyword">int</span> queue_size = <span class="number">256</span>, <span class="keyword">int</span> flags = <span class="number">0</span>) : m_queue_size(queue_size)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (thread_count &lt;= <span class="number">0</span> || thread_count &gt; MAX_THREADS || queue_size &lt;= <span class="number">0</span> || queue_size &gt; MAX_QUEUE)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">&quot;argument eeror&quot;</span> &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>-&gt;m_thread_count = <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//this-&gt;m_queue_size = queue_size;</span></span><br><span class="line">        <span class="keyword">this</span>-&gt;m_head = <span class="keyword">this</span>-&gt;m_tail = <span class="keyword">this</span>-&gt;m_count = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_shutdown = <span class="keyword">this</span>-&gt;m_started = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>-&gt;m_threads = <span class="keyword">new</span> <span class="keyword">pthread_t</span>[thread_count];</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_queue = <span class="keyword">new</span> threadpool_task[queue_size];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> ((pthread_mutex_init(&amp;<span class="keyword">this</span>-&gt;m_lock, <span class="literal">nullptr</span>) != <span class="number">0</span>) ||</span><br><span class="line">            (pthread_cond_init(&amp;<span class="keyword">this</span>-&gt;m_notify, <span class="literal">NULL</span>) != <span class="number">0</span>) ||</span><br><span class="line">            (<span class="keyword">this</span>-&gt;m_threads == <span class="literal">nullptr</span>) || (<span class="keyword">this</span>-&gt;m_queue == <span class="literal">nullptr</span>))</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">&quot;init eeror&quot;</span> &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; thread_count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (pthread_create(&amp;<span class="keyword">this</span>-&gt;m_threads[i], <span class="literal">nullptr</span>, threadpool_thread, <span class="keyword">this</span>) != <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">&quot;create &quot;</span> &lt;&lt; i &lt;&lt; <span class="string">&quot; thread error&quot;</span> &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">this</span>-&gt;m_thread_count++;</span><br><span class="line">            <span class="keyword">this</span>-&gt;m_started++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">while</span> (<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="线程池析构函数"><a href="#线程池析构函数" class="headerlink" title="线程池析构函数"></a>线程池析构函数</h1><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><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">threadpool::~threadpool()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span> == <span class="literal">NULL</span> || <span class="keyword">this</span>-&gt;m_started &gt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>-&gt;m_threads)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">delete</span>[] <span class="keyword">this</span>-&gt;m_threads;</span><br><span class="line">        <span class="keyword">delete</span>[] <span class="keyword">this</span>-&gt;m_queue;</span><br><span class="line"></span><br><span class="line">        pthread_mutex_lock(&amp;(<span class="keyword">this</span>-&gt;m_lock));</span><br><span class="line">        pthread_mutex_destroy(&amp;(<span class="keyword">this</span>-&gt;m_lock));</span><br><span class="line">        pthread_cond_destroy(&amp;(<span class="keyword">this</span>-&gt;m_notify));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//delete[] this;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>以下函数基本没啥变化</strong></p><h1 id="添加任务函数"><a href="#添加任务函数" class="headerlink" title="添加任务函数"></a>添加任务函数</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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">threadpool::threadpool_add</span><span class="params">(threadpool *pool, <span class="keyword">void</span> (*function)(<span class="keyword">void</span> *), <span class="keyword">void</span> *argument, <span class="keyword">int</span> flag)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> err = <span class="number">0</span>, next;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pool == <span class="literal">nullptr</span> || function == <span class="literal">nullptr</span>)</span><br><span class="line">        <span class="keyword">return</span> threadpool_invalid;</span><br><span class="line">    <span class="keyword">if</span> (pthread_mutex_lock(&amp;(pool-&gt;m_lock)) != <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> threadpool_lock_failure;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    next = pool-&gt;m_tail + <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    next = (next == pool-&gt;m_queue_size) ? <span class="number">0</span> : next;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (pool-&gt;m_count == pool-&gt;m_queue_size)</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_queue_full;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        pool-&gt;m_queue[pool-&gt;m_tail].function = function;</span><br><span class="line">        pool-&gt;m_queue[pool-&gt;m_tail].argument = argument;</span><br><span class="line"></span><br><span class="line">        pool-&gt;m_tail = next;</span><br><span class="line">        pool-&gt;m_count++;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (pthread_cond_signal(&amp;(pool-&gt;m_notify)) != <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_lock_failure;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">while</span> (<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pthread_mutex_unlock(&amp;(pool-&gt;m_lock)) != <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        err = threadpool_lock_failure;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> err;</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 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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">threadpool::threadpoolexit</span><span class="params">(threadpool *pool, <span class="keyword">int</span> flag)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> i, err = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pool == <span class="literal">nullptr</span>)</span><br><span class="line">        <span class="keyword">return</span> threadpool_invalid;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pthread_mutex_lock(&amp;(pool-&gt;m_lock)) != <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">return</span> threadpool_lock_failure;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (pool-&gt;m_shutdown)</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_shutdown;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        pool-&gt;m_shutdown = (flag &amp; threadpool_graceful) ? graceful_shutdown : immediate_shutdown;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> ((pthread_cond_broadcast(&amp;(pool-&gt;m_notify)) != <span class="number">0</span>) || (pthread_mutex_unlock(&amp;(pool-&gt;m_lock)) != <span class="number">0</span>))</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_lock_failure;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; pool-&gt;m_thread_count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (pthread_join(pool-&gt;m_threads[i], <span class="literal">nullptr</span>) != <span class="number">0</span>)</span><br><span class="line">                err = threadpool_thread_failure;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">while</span> (<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> err;</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 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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> *<span class="title">threadpool::threadpool_thread</span><span class="params">(<span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    threadpool *pool = <span class="keyword">static_cast</span>&lt;threadpool *&gt;(arg);</span><br><span class="line">    threadpool_task task;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (;;)</span><br><span class="line">    &#123;</span><br><span class="line">        pthread_mutex_lock(&amp;(pool-&gt;m_lock));</span><br><span class="line">        <span class="keyword">while</span> ((pool-&gt;m_count == <span class="number">0</span>) &amp;&amp; (!pool-&gt;m_shutdown))</span><br><span class="line">        &#123;</span><br><span class="line">            pthread_cond_wait(&amp;(pool-&gt;m_notify), &amp;(pool-&gt;m_lock));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> ((pool-&gt;m_shutdown == immediate_shutdown) || ((pool-&gt;m_shutdown == graceful_shutdown) &amp;&amp; (pool-&gt;m_count == <span class="number">0</span>)))</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        task.function = pool-&gt;m_queue[pool-&gt;m_head].function;</span><br><span class="line">        task.argument = pool-&gt;m_queue[pool-&gt;m_head].argument;</span><br><span class="line"></span><br><span class="line">        pool-&gt;m_head++;</span><br><span class="line">        pool-&gt;m_head = (pool-&gt;m_head == pool-&gt;m_queue_size) ? <span class="number">0</span> : pool-&gt;m_head;</span><br><span class="line">        pool-&gt;m_count--;</span><br><span class="line"></span><br><span class="line">        pthread_mutex_unlock(&amp;(pool-&gt;m_lock));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// (*(task.function))(task.argument);</span></span><br><span class="line"></span><br><span class="line">        task.function(task.argument);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    pool-&gt;m_started--;</span><br><span class="line">    pthread_mutex_unlock(&amp;(pool-&gt;m_lock));</span><br><span class="line">    pthread_exit(<span class="literal">nullptr</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nullptr</span>;</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 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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;threadpool.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> THREAD 32</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> QUEUE 256</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> tasks = <span class="number">0</span>, done = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">pthread_mutex_t</span> lock;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dumy_task</span><span class="params">(<span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    usleep(<span class="number">10000</span>);</span><br><span class="line">    pthread_mutex_lock(&amp;lock);</span><br><span class="line"></span><br><span class="line">    done++;</span><br><span class="line">    pthread_mutex_unlock(&amp;lock);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span>, <span class="keyword">char</span> **)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    threadpool *pool = <span class="keyword">new</span> threadpool(THREAD, QUEUE, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    pthread_mutex_init(&amp;lock, <span class="literal">nullptr</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">&quot;pool started with &quot;</span> &lt;&lt; THREAD &lt;&lt; <span class="string">&quot; threads and queue size of &quot;</span> &lt;&lt; QUEUE &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> ((pool-&gt;threadpool_add(pool, &amp;dumy_task, <span class="literal">nullptr</span>, <span class="number">0</span>)) == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        pthread_mutex_lock(&amp;lock);</span><br><span class="line">        tasks++;</span><br><span class="line">        pthread_mutex_unlock(&amp;lock);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">&quot;add &quot;</span> &lt;&lt; tasks &lt;&lt; <span class="string">&quot; tasks&quot;</span> &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> ((tasks / <span class="number">2</span>) &gt; done)</span><br><span class="line">    &#123;</span><br><span class="line">        usleep(<span class="number">10000</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//pool-&gt;threadpoolexit(pool, 0) == 0;</span></span><br><span class="line">    assert(pool-&gt;threadpoolexit(pool, <span class="number">0</span>) == <span class="number">0</span>);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">&quot;did &quot;</span> &lt;&lt; done &lt;&lt; <span class="string">&quot; tasks&quot;</span> &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span>[] pool;</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><span class="line"></span><br></pre></td></tr></table></figure><h1 id="CMakeLists文件"><a href="#CMakeLists文件" class="headerlink" title="CMakeLists文件"></a>CMakeLists文件</h1><figure class="highlight cmake"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.0</span>.<span class="number">0</span>)</span><br><span class="line"><span class="keyword">project</span>(threadpool_cpp VERSION <span class="number">0.1</span>.<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">include</span>(CTest)</span><br><span class="line"><span class="keyword">enable_testing</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">add_executable</span>(threadpool_cpp main.cpp threadpool.cpp threadpool.h)</span><br><span class="line"></span><br><span class="line"><span class="keyword">find_package</span>(Threads)</span><br><span class="line"><span class="keyword">target_link_libraries</span>(threadpool_cpp <span class="variable">$&#123;CMAKE_THREAD_LIBS_INIT&#125;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">set</span>(CPACK_PROJECT_NAME <span class="variable">$&#123;PROJECT_NAME&#125;</span>)</span><br><span class="line"><span class="keyword">set</span>(CPACK_PROJECT_VERSION <span class="variable">$&#123;PROJECT_VERSION&#125;</span>)</span><br><span class="line"><span class="keyword">include</span>(CPack)</span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="测试效果图"><a href="#测试效果图" class="headerlink" title="测试效果图"></a>测试效果图</h1><p><img src="/2021/06/07/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AE%9E%E7%8E%B0-C-%E7%89%88%E6%9C%AC/image-20210607203945887.png" alt="image-20210607203945887"></p>]]></content>
    
    
    <summary type="html">学习了c++，把线程池改成c++试试</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="C++" scheme="https://ethereal14.github.io/tags/C/"/>
    
  </entry>
  
  <entry>
    <title>Linux高性能服务器编程</title>
    <link href="https://ethereal14.github.io/2021/05/20/Linux%E9%AB%98%E6%80%A7%E8%83%BD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%96%E7%A8%8B/"/>
    <id>https://ethereal14.github.io/2021/05/20/Linux%E9%AB%98%E6%80%A7%E8%83%BD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%96%E7%A8%8B/</id>
    <published>2021-05-20T04:34:56.000Z</published>
    <updated>2023-03-12T16:03:10.141Z</updated>
    
    <content type="html"><![CDATA[<h2 id="TCP-IP协议族"><a href="#TCP-IP协议族" class="headerlink" title="TCP/IP协议族"></a>TCP/IP协议族</h2><h3 id="TCP-IP协议族体系结构以及主要协议"><a href="#TCP-IP协议族体系结构以及主要协议" class="headerlink" title="TCP/IP协议族体系结构以及主要协议"></a>TCP/IP协议族体系结构以及主要协议</h3><p>四层协议模型：</p><h2 id="Linux网络编程基础API"><a href="#Linux网络编程基础API" class="headerlink" title="Linux网络编程基础API"></a>Linux网络编程基础API</h2><h3 id="socket地址API"><a href="#socket地址API" class="headerlink" title="socket地址API"></a>socket地址API</h3><h4 id="主机字节序和网络字节序"><a href="#主机字节序和网络字节序" class="headerlink" title="主机字节序和网络字节序"></a>主机字节序和网络字节序</h4><ul><li><p>大端字节序：高存低，低存高</p></li><li><p>小端字节序：高存高，低存低</p></li><li><p>主机字节序—-小端存储</p></li><li><p>网络字节序—-大端存储</p></li><li><p>一台机器上的两个进程间通信也需要字节序转换(jvm就是大端存储)</p></li><li><p>主机字节序和网络字节序转换API</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">int</span> <span class="title">htonl</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">int</span> hostlong)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">short</span> <span class="keyword">int</span> <span class="title">htons</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">short</span> <span class="keyword">int</span> hostshort)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">int</span> <span class="title">ntohl</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">int</span> netlong)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">short</span> <span class="keyword">int</span> <span class="title">ntohs</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">short</span> <span class="keyword">int</span> netshort)</span></span>;</span><br></pre></td></tr></table></figure><ul><li>长整型通常用来转换IP地址、短整型用来转换端口号</li></ul></li></ul><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">byteorder</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="class"><span class="keyword">union</span></span></span><br><span class="line"><span class="class">    &#123;</span></span><br><span class="line">        <span class="keyword">short</span> value;</span><br><span class="line">        <span class="keyword">char</span> union_bytes[<span class="keyword">sizeof</span>(<span class="keyword">short</span>)];</span><br><span class="line">    &#125; test;</span><br><span class="line"></span><br><span class="line">    test.value = <span class="number">0x0102</span>;</span><br><span class="line">    <span class="keyword">if</span> ((test.union_bytes[<span class="number">0</span>] == <span class="number">1</span>) &amp;&amp; (test.union_bytes[<span class="number">1</span>] == <span class="number">2</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;big endian\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> ((test.union_bytes[<span class="number">0</span>] == <span class="number">2</span>) &amp;&amp; (test.union_bytes[<span class="number">1</span>] == <span class="number">1</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;little endian\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;unknown....\n&quot;</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="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">const</span> <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">    byteorder();</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><h4 id="通用socket地址"><a href="#通用socket地址" class="headerlink" title="通用socket地址"></a>通用socket地址</h4><p><strong>socket网络编程接口中表示socket地址的是结构体sockaddr，定义如下：</strong></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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;bits/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">sa_family_t</span> sa_family;</span><br><span class="line">    <span class="keyword">char</span> sa_data[<span class="number">14</span>];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li><p>sa_family成员是地址族类型变量。</p><table><thead><tr><th>协议族</th><th>地址族</th><th>描述</th></tr></thead><tbody><tr><td>PF_UNIX</td><td>AF_UNIX</td><td>UNIX本地域协议族</td></tr><tr><td>PF_INET</td><td>AF_INET</td><td>TCP/IPv4协议族</td></tr><tr><td>PF_INET6</td><td>AF_INET6</td><td>TCP/IPv6协议族</td></tr></tbody></table></li></ol><ul><li>宏PF_ 和 AF_都定义在bis/socket.h文件中，两者值完全相同，所以常常混用</li><li>sa_data成员用于存放socket地址值。但是不同的协议族地址值有不同含义和长度<table><thead><tr><th>协议族</th><th>地址值含义和长度</th></tr></thead><tbody><tr><td>PF_UNIX</td><td>文件的路径名，长度可达108字节</td></tr><tr><td>PF_INET</td><td>16bit端口号和32bitIPv4地址，共6字节</td></tr><tr><td>PF_INET6</td><td>16bit端口号、32bit流标识、128bitIPv6地址，32bit范围ID，共26字节</td></tr></tbody></table></li></ul><p>下边也是通用的socket结构体</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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;bits/socket.h&gt;</span></span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_storage</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">sa_family_t</span> sa_family;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">int</span> __ss_align;</span><br><span class="line">    <span class="keyword">char</span> __ss_padding[<span class="number">128</span>-<span class="keyword">sizeof</span>(__ss_align)];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="专用socket地址"><a href="#专用socket地址" class="headerlink" title="专用socket地址"></a>专用socket地址</h4><p><strong><em>通用socket地址不好用，用Linux提供的专用socket地址结构体</em></strong></p><ol><li><code>sockaddr_un</code> 为 本地套接字</li><li><code>sockaddr_in</code> 为 ipv4</li><li><code>sockaddr_in6</code> 为 ipv6</li></ol><p><strong>重点为ipv4：</strong></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><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"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">sa_family_t</span> sa_family; <span class="comment">//地址族：AF_INET</span></span><br><span class="line">    <span class="keyword">u_int16_t</span> sin_port;<span class="comment">//端口号，要用网络字节序表示</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">sin_addr</span>;</span><span class="comment">//IPv4地址结构体</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">u_int32_t</span> s_addr;<span class="comment">//IPv4地址，要用网络字节序表示</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong><em>所有专用socket地址类型变量在使用的时候都必须强转为sockaddr类型</em></strong></p><h4 id="IP地址转换函数"><a href="#IP地址转换函数" class="headerlink" title="IP地址转换函数"></a>IP地址转换函数</h4><p>编程中需要把点分十进制(192.168.1.117)转换成整数(二进制数)</p><p>ipv4使用以下函数转换:</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *将点分十进制字符串表示的IPv4地址转化为网络字节序整数表示的地址。</span></span><br><span class="line"><span class="comment"> *失败返回INADDR_NONE</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">in_addr_t</span> <span class="title">inet_addr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *strptr)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *功能和inet_addr一样：将点分十进制字符串表示的IPv4地址转化为网络字节序整数表示的地址。</span></span><br><span class="line"><span class="comment"> * 但是将转化结果存储与参数inp指向的地址结构中</span></span><br><span class="line"><span class="comment"> *成功返回 1</span></span><br><span class="line"><span class="comment"> *失败返回 0</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">inet_aton</span><span class="params">(<span class="keyword">const</span>* cp,struct in_addr* inp)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *将网络字节序整数表示的IPv4地址转化为点分十进制字符串表示的地址。</span></span><br><span class="line"><span class="comment"> * 但是将转化结果存储与参数inp指向的地址结构中</span></span><br><span class="line"><span class="comment"> *该函数不可重入</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">char</span> *<span class="title">inet_ntoa</span><span class="params">(struct in_addr in)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *将点分十进制字符串src表示的IP(v4、v6)地址转化为网络字节序整数表示的地址,并把转换结果存储与dst指向的内存中。</span></span><br><span class="line"><span class="comment"> * af：地址族</span></span><br><span class="line"><span class="comment"> * 成功返回 1</span></span><br><span class="line"><span class="comment"> *失败返回 0 errno</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">inet_pton</span><span class="params">(<span class="keyword">int</span> af,<span class="keyword">const</span> <span class="keyword">char</span>*src,<span class="keyword">void</span> *dst)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *与inet_pton作相反转换</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span> *<span class="title">inet_ntop</span><span class="params">(<span class="keyword">int</span> af,<span class="keyword">const</span> <span class="keyword">void</span> *src,<span class="keyword">char</span> *dst,<span class="keyword">socklen_t</span> cnt)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="创建socket-socket函数"><a href="#创建socket-socket函数" class="headerlink" title="创建socket(socket函数)"></a>创建socket(socket函数)</h3><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><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* domain:  协议族  PF_INET、PF_INET6、PF_UNIX</span></span><br><span class="line"><span class="comment">* type:  服务类型   SOCK_STREAM、SOCK_DGRAM</span></span><br><span class="line"><span class="comment">* protocol: 0</span></span><br><span class="line"><span class="comment">* 返回值:  成功返回 文件描述符, 失败返回-1, errno</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">socket</span><span class="params">(<span class="keyword">int</span> domain, <span class="keyword">int</span> type, <span class="keyword">int</span> protocol)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="命名socket-bind函数"><a href="#命名socket-bind函数" class="headerlink" title="命名socket(bind函数)"></a>命名socket(bind函数)</h3><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><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* bind绑定失败时, 会返回errno</span></span><br><span class="line"><span class="comment">* 常见的errno:</span></span><br><span class="line"><span class="comment">* EACCES 被绑定的地址是受保护的</span></span><br><span class="line"><span class="comment">* EADDRINUSE被绑定的地址正在使用中, 比如将地址绑定到处于TIME_WAIT状态的socket地址</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">bind</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">const</span> struct sockaddr* my_addr, <span class="keyword">socklen_t</span> addrlen)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="监听socket-listen函数"><a href="#监听socket-listen函数" class="headerlink" title="监听socket(listen函数)"></a>监听socket(listen函数)</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* backlog 表示内核监听队列的最大长度(只表示完全连接状态的socket上限)</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">listen</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">int</span> backlog)</span></span>;</span><br></pre></td></tr></table></figure><p>一下代码是backlog参数对listen的影响</p><p><em>处于ESTABLISHED(数据传输)状态的为backlog+1</em></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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">bool</span> stop = <span class="literal">false</span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">handler_term</span><span class="params">(<span class="keyword">int</span> sig)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    stop = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    signal(SIGTERM, handler_term);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (argc &lt;= <span class="number">3</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;usage: %s ip_address port_number backlog\n&quot;</span>, basename(argv[<span class="number">0</span>]));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *ip = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">int</span> port = atoi(argv[<span class="number">2</span>]);</span><br><span class="line">    <span class="keyword">int</span> backlog = atoi(argv[<span class="number">3</span>]);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sock = socket(PF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(sock &gt;= <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">address</span>;</span></span><br><span class="line">    bzero(&amp;address, <span class="keyword">sizeof</span>(address));</span><br><span class="line">    address.sin_family = PF_INET;</span><br><span class="line">    inet_pton(AF_INET, ip, &amp;address.sin_addr);</span><br><span class="line">    address.sin_port = htons(port);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> ret = bind(sock, (struct sockaddr *)&amp;address, <span class="keyword">sizeof</span>(address));</span><br><span class="line">    assert(ret != <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    ret = listen(sock, backlog);</span><br><span class="line">    assert(ret != <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (!stop)</span><br><span class="line">    &#123;</span><br><span class="line">        sleep(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    close(sock);</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><h3 id="接受连接-accpet函数"><a href="#接受连接-accpet函数" class="headerlink" title="接受连接(accpet函数)"></a>接受连接(accpet函数)</h3><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* sockfd listen函数中的socket</span></span><br><span class="line"><span class="comment">* addr 远端socket地址</span></span><br><span class="line"><span class="comment">* addrlen 远端socket地址长度 </span></span><br><span class="line"><span class="comment">* 返回值 </span></span><br><span class="line"><span class="comment">*成功 返回一个新的连接socket</span></span><br><span class="line"><span class="comment">* 失败 返回 -1 并设置 errno</span></span><br><span class="line"><span class="comment">* 成功返回的socket唯一标识了被接受的这个连接，服务器可通过读写该socket来与被接受连接对应的客户端通信</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">accept</span><span class="params">(<span class="keyword">int</span> sockfd, struct sockaddr* addr,<span class="keyword">socklen_t</span>* addrlen)</span></span>;</span><br></pre></td></tr></table></figure><p><strong>如果监听队列中处于ESTABLISTEN状态的客户端断开连接，accept()函数依然可以成功返回。accept()函数只是从监听队列中取出连接，不管连接处于何种状态</strong></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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">const</span> <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> server_sock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">server_addr</span>;</span></span><br><span class="line"></span><br><span class="line">    server_sock = socket(PF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(server_sock &gt;= <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    server_addr.sin_family = AF_INET;</span><br><span class="line">    server_addr.sin_port = htons(<span class="number">8080</span>);</span><br><span class="line">    server_addr.sin_addr.s_addr = INADDR_ANY;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> ret = bind(server_sock, (struct sockaddr *)&amp;server_addr, <span class="keyword">sizeof</span>(server_addr));</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    ret = listen(server_sock, <span class="number">5</span>);</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    sleep(<span class="number">20</span>);</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">client_addr</span>;</span></span><br><span class="line">    <span class="keyword">socklen_t</span> client_addrlen = <span class="keyword">sizeof</span>(client_addr);</span><br><span class="line">    <span class="keyword">int</span> connfd = accept(server_sock, (struct sockaddr *)&amp;client_addr, &amp;client_addrlen);</span><br><span class="line">    <span class="keyword">if</span> (connfd &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;errno is %d\n&quot;</span>, errno);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">char</span> remote[INET_ADDRSTRLEN];</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;connect with ip : %s and port is : %d\n&quot;</span>, inet_ntop(AF_INET, &amp;client_addr.sin_addr, remote, INET_ADDRSTRLEN),</span><br><span class="line">               ntohs(client_addr.sin_port));</span><br><span class="line"></span><br><span class="line">        close(connfd);</span><br><span class="line">    &#125;</span><br><span class="line">    close(server_sock);</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><h3 id="发起连接"><a href="#发起连接" class="headerlink" title="发起连接"></a>发起连接</h3><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><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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">*sockfd 客户端使用socket新建的sockfd</span></span><br><span class="line"><span class="comment">*serv_addr 服务器监听的地址</span></span><br><span class="line"><span class="comment">*addr_len 地址长度</span></span><br><span class="line"><span class="comment">*返回值</span></span><br><span class="line"><span class="comment">*成功返回 0</span></span><br><span class="line"><span class="comment">*失败返回 -1 并设置 errno</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">connect</span><span class="params">(<span class="keyword">int</span> sockfd,<span class="keyword">const</span> struct sockaddr*serv_addr,<span class="keyword">socklen_t</span> addrlen)</span></span>;</span><br></pre></td></tr></table></figure><ul><li>常见errno<ul><li>ECONNREFUSED: 目标端口不存在，连接被拒绝</li><li>ETIMEDOUT: 连接超时</li></ul></li></ul><h3 id="关闭连接"><a href="#关闭连接" class="headerlink" title="关闭连接"></a>关闭连接</h3><p><em>不是立即关闭一个连接，而是将fd的引用数-1，fd的引用为0时才是真正关闭</em></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="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">close</span><span class="params">(<span class="keyword">int</span> fd)</span></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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">shutdown</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">int</span> howto)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="数据读写"><a href="#数据读写" class="headerlink" title="数据读写"></a>数据读写</h3><h4 id="TCP数据读写"><a href="#TCP数据读写" class="headerlink" title="TCP数据读写"></a>TCP数据读写</h4><p>对比read、write函数增加了对数据读写的控制。</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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">recv</span><span class="params">(<span class="keyword">int</span> sockfd,<span class="keyword">void</span> *buf,<span class="keyword">size_t</span> len,<span class="keyword">int</span> flag)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">send</span><span class="params">(<span class="keyword">int</span> sockfd,<span class="keyword">const</span> <span class="keyword">void</span> *buf)</span></span></span><br></pre></td></tr></table></figure><p>flag参数为数据读写提供了额外的控制</p><table><thead><tr><th>选项名</th><th>含义</th><th>send</th><th>recv</th></tr></thead><tbody><tr><td>MSG_CONFIRM</td><td>指示数据链路层协议持续监听对方的回应，直到得到答复，它仅能用于SOCK_DGRAM和SOCK_RAW类型的socket</td><td>Y</td><td>N</td></tr><tr><td>MSG_DONTROUTE</td><td>不查看路由表，直接将数据发送给本地局域网内的主机。这表示发送者确切的知道目标主机就在本地网络上</td><td>Y</td><td>N</td></tr><tr><td>MSG_DONTWAIT</td><td>对socket的此次操作将是非阻塞的</td><td>Y</td><td>Y</td></tr><tr><td>MSG_MORE</td><td>告诉内核应用程序还有更多数据要发送，内核将超时等待新数据写入TCP发送缓冲区后一并发送。这样可以防止TCP发送过多小的报文段，从而提高传输效率</td><td>Y</td><td>N</td></tr><tr><td>MSG_WAITALL</td><td>读操作仅在读取到指定数量的字节后才返回</td><td>N</td><td>Y</td></tr><tr><td>MSG_PEEK</td><td>窥探读缓存中的数据，此次读操作不会导致这些数据被清除</td><td>N</td><td>Y</td></tr><tr><td>MSG_OOB</td><td>发送或接收紧急数据</td><td>Y</td><td>Y</td></tr><tr><td>MSG_NOSIGNAL</td><td>往读端关闭的管道或者socket连接中写数据时不引发SIGPIPE信号</td><td>Y</td><td>N</td></tr></tbody></table><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//发送带外数据</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (argc &lt; <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s ip_address port_number\n&quot;</span>,</span><br><span class="line">               basename(argv[<span class="number">0</span>]));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *ip = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">int</span> port = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">server_address</span>;</span></span><br><span class="line">    bzero(&amp;server_address, <span class="keyword">sizeof</span>(server_address));</span><br><span class="line">    server_address.sin_family = AF_INET;</span><br><span class="line">    server_address.sin_port = htons(port);</span><br><span class="line">    inet_pton(AF_INET, ip, &amp;server_address.sin_addr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sockfd = socket(PF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(sockfd &gt;= <span class="number">0</span>);</span><br><span class="line">    <span class="keyword">if</span> (connect(sockfd, (struct sockaddr *)&amp;server_address,</span><br><span class="line">                <span class="keyword">sizeof</span>(server_address)) &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;connect failed\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">const</span> <span class="keyword">char</span> *oob_data = <span class="string">&quot;abc&quot;</span>;</span><br><span class="line">        <span class="keyword">const</span> <span class="keyword">char</span> *normal_data = <span class="string">&quot;123&quot;</span>;</span><br><span class="line">        send(sockfd, normal_data, <span class="built_in">strlen</span>(normal_data), <span class="number">0</span>);</span><br><span class="line">        send(sockfd, oob_data, <span class="built_in">strlen</span>(oob_data), MSG_OOB);</span><br><span class="line">        send(sockfd, normal_data, <span class="built_in">strlen</span>(normal_data), <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    close(sockfd);</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><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//接收带外数据</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUF_SIZE 1024</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (argc &lt; <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s ip_address port_number\n&quot;</span>, basename(argv[<span class="number">0</span>]));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *ip = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">int</span> port = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">address</span>;</span></span><br><span class="line">    bzero(&amp;address, <span class="keyword">sizeof</span>(address));</span><br><span class="line">    address.sin_family = AF_INET;</span><br><span class="line">    inet_pton(AF_INET, ip, &amp;address.sin_addr);</span><br><span class="line">    address.sin_port = htons(port);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sock = socket(PF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(sock &gt;= <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> ret = bind(sock, (struct sockaddr *)&amp;address, <span class="keyword">sizeof</span>(address));</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    ret = listen(sock, <span class="number">5</span>);</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">client</span>;</span></span><br><span class="line">    <span class="keyword">socklen_t</span> client_addrlength = <span class="keyword">sizeof</span>(client);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> connfd = accept(sock, (struct sockaddr *)&amp;client, &amp;client_addrlength);</span><br><span class="line">    <span class="keyword">if</span> (connfd &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;errno is:%d\n&quot;</span>, errno);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">char</span> buffer[BUF_SIZE];</span><br><span class="line"></span><br><span class="line">        <span class="built_in">memset</span>(buffer, <span class="string">&#x27;\0&#x27;</span>, BUF_SIZE);</span><br><span class="line">        ret = recv(connfd, buffer, BUF_SIZE - <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;got %d bytes of normal data &#x27;%s&#x27;\n&quot;</span>, ret, buffer);</span><br><span class="line"></span><br><span class="line">        <span class="built_in">memset</span>(buffer, <span class="string">&#x27;\0&#x27;</span>, BUF_SIZE);</span><br><span class="line">        ret = recv(connfd, buffer, BUF_SIZE - <span class="number">1</span>, MSG_OOB);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;got %d bytes of oob data &#x27;%s&#x27;\n&quot;</span>, ret, buffer);</span><br><span class="line"></span><br><span class="line">        <span class="built_in">memset</span>(buffer, <span class="string">&#x27;\0&#x27;</span>, BUF_SIZE);</span><br><span class="line">        ret = recv(connfd, buffer, BUF_SIZE - <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;got %d bytes of normal data &#x27;%s&#x27;\n&quot;</span>, ret, buffer);</span><br><span class="line"></span><br><span class="line">        close(connfd);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    close(sock);</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><h4 id="UDP数据读写"><a href="#UDP数据读写" class="headerlink" title="UDP数据读写"></a>UDP数据读写</h4><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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">recvfrom</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">void</span>* buf, <span class="keyword">size_t</span> len, <span class="keyword">int</span> flags,struct sockaddr* src_addr, <span class="keyword">socklen_t</span>*addrlen)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">sendto</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">const</span> <span class="keyword">void</span>* buf, <span class="keyword">size_t</span> len, <span class="keyword">int</span> flags, <span class="keyword">const</span> struct sockaddr* dest_addr,<span class="keyword">socklen_t</span> addrlen)</span></span>;</span><br></pre></td></tr></table></figure><p><em>recvfrom和sendto也可用于面向连接的socket，只需要把最后两个参数设置为NULL以忽略发送端/接收端的socket地址</em></p><h4 id="通用数据读写"><a href="#通用数据读写" class="headerlink" title="通用数据读写"></a>通用数据读写</h4><p>以下两个函数不仅能用于TCP流数据，也能用于UDP数据报</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">recvmsg</span><span class="params">(<span class="keyword">int</span> sockfd, struct msghdr* msg, <span class="keyword">int</span> flags)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">ssize_t</span> <span class="title">sendmsg</span><span class="params">(<span class="keyword">int</span> sockfd, struct msghdr* msg, <span class="keyword">int</span> flags)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/***** msghdr结构体定义 *****/</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">msghdr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">void</span> *msg_name;           <span class="comment">//socket地址</span></span><br><span class="line">    <span class="keyword">socklen_t</span> msg_namelen;    <span class="comment">//socket地址的长度</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">iovec</span> *<span class="title">msg_iov</span>;</span>    <span class="comment">//分散的内存块</span></span><br><span class="line">    <span class="keyword">int</span> msg_iovlen;           <span class="comment">//分散内存数量</span></span><br><span class="line">    <span class="keyword">void</span> *msg_control;        <span class="comment">//指向辅助数据的其实位置</span></span><br><span class="line">    <span class="keyword">socklen_t</span> msg_controllen; <span class="comment">//辅助数据的大小</span></span><br><span class="line">    <span class="keyword">int</span> msg_flags;            <span class="comment">//复制函数中的flags参数，并在调用过程中更新</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>msg_name</code>参数对于TCP来说不用设置。</p><h3 id="带外标记"><a href="#带外标记" class="headerlink" title="带外标记"></a>带外标记</h3><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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//判断sockfd是否带外标记</span></span><br><span class="line"><span class="comment">//是 返回 1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">sockatmark</span><span class="params">(<span class="keyword">int</span> sockfd)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="地址信息函数"><a href="#地址信息函数" class="headerlink" title="地址信息函数"></a>地址信息函数</h3><p>想知道连接socket的本端socket地址，以及远端socket地址，用以下函数</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="comment">//获取本端socket地址</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">getsockname</span><span class="params">(<span class="keyword">int</span> sockfd, struct sockaddr* address,<span class="keyword">socklen_t</span>* address_len)</span></span>;</span><br><span class="line"><span class="comment">//获取远端socket地址</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">getpeername</span><span class="params">(<span class="keyword">int</span> sockfd, struct sockaddr* address,<span class="keyword">socklen_t</span>* address_len)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="socket选项"><a href="#socket选项" class="headerlink" title="socket选项"></a>socket选项</h3><p>以下函数为socket文件描述符属性读取和设置专用</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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//level参数指定要操作哪个协议的选项(IPv4、IPv6、TCP等)</span></span><br><span class="line"><span class="comment">//option_name参数指定选项名字</span></span><br><span class="line"><span class="comment">//option_value指定被操作选项的值、option_len长度</span></span><br><span class="line"><span class="comment">//成功返回0、失败返回-1，并设置errno</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">getsockopt</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">int</span> level, <span class="keyword">int</span> option_name, <span class="keyword">void</span>* option_value, <span class="keyword">socklen_t</span>* <span class="keyword">restrict</span> option_len)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">setsockopt</span><span class="params">(<span class="keyword">int</span> sockfd, <span class="keyword">int</span> level, <span class="keyword">int</span> option_name, <span class="keyword">const</span> <span class="keyword">void</span>* option_value, <span class="keyword">socklen_t</span>* <span class="keyword">restrict</span> option_len)</span></span>;</span><br></pre></td></tr></table></figure><p><img src="/2021/05/20/Linux%E9%AB%98%E6%80%A7%E8%83%BD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%96%E7%A8%8B/image-20210721193914528.png" alt="image-20210721193914528"></p><p><em>部分socket选项设置应该在listen/connect函数之前完成</em></p><h4 id="SO-REUSEADDR选项"><a href="#SO-REUSEADDR选项" class="headerlink" title="SO_REUSEADDR选项"></a>SO_REUSEADDR选项</h4><p>主动关闭连接端会经历<code>TIME_WAIT</code>状态，这个时候可以用<code>SO_REUSEADDR</code>来强制使用被处于<code>TIME_WAIT</code>状态的连接占用的socket地址。</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><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="keyword">int</span> sock = socket(PF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">assert(sock &gt;= <span class="number">0</span>);</span><br><span class="line"><span class="keyword">int</span> reuse = <span class="number">1</span>;</span><br><span class="line">setsockopt(sock, SOL_SOCKET, SO_REUSERADDR,&amp;reuse,<span class="keyword">sizeof</span>(reuse));</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">address</span>;</span></span><br><span class="line">bzero(&amp;address,<span class="keyword">sizeof</span>(address));</span><br><span class="line">address.sin_family = AF_INET;</span><br><span class="line">inet_pton(AF_INET,ip,&amp;address.sin_addr);</span><br><span class="line">address.sin_port = htons(port);</span><br><span class="line"><span class="keyword">int</span> ret = bind(sock,(struct sockaddr_in*)&amp;address,<span class="keyword">sizeof</span>(address));</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (argc &lt; <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s ip_address, port_number\n&quot;</span>, basename(argv[<span class="number">0</span>]));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">char</span> *ip = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">int</span> port = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sockfd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(sockfd &gt;= <span class="number">0</span>);</span><br><span class="line">    <span class="keyword">int</span> reuse = <span class="number">1</span>;</span><br><span class="line">    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &amp;reuse, <span class="keyword">sizeof</span>(reuse));</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">server_address</span>;</span></span><br><span class="line">    bzero(&amp;server_address, <span class="keyword">sizeof</span>(server_address));</span><br><span class="line">    server_address.sin_family = AF_INET;</span><br><span class="line">    server_address.sin_port = htons(port);</span><br><span class="line">    inet_pton(AF_INET, ip, &amp;server_address.sin_addr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> ret;</span><br><span class="line">    ret = bind(sockfd, (struct sockaddr *)&amp;server_address, <span class="keyword">sizeof</span>(server_address));</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    ret = listen(sockfd, <span class="number">5</span>);</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">client_address</span>;</span></span><br><span class="line">    <span class="keyword">socklen_t</span> client_address_len = <span class="keyword">sizeof</span>(client_address);</span><br><span class="line">    <span class="keyword">int</span> connfd = accept(sockfd, (struct sockaddr *)&amp;client_address, &amp;client_address_len);</span><br><span class="line">    <span class="keyword">if</span> (connfd &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;errno is:%d\n&quot;</span>, errno);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">char</span> remote[INET_ADDRSTRLEN];</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;connected with ip:%s and port:%d\n&quot;</span>,</span><br><span class="line">               inet_ntop(AF_INET, &amp;client_address.sin_addr,</span><br><span class="line">                         remote, INET_ADDRSTRLEN),</span><br><span class="line">               htons(client_address.sin_port));</span><br><span class="line">        close(connfd);</span><br><span class="line">    &#125;</span><br><span class="line">    close(sockfd);</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><h4 id="SO-RCVBUF和SO-SNDBUF选项"><a href="#SO-RCVBUF和SO-SNDBUF选项" class="headerlink" title="SO_RCVBUF和SO_SNDBUF选项"></a>SO_RCVBUF和SO_SNDBUF选项</h4><p>设置TCP接收、发送缓冲区大小。使用setsockopt设置缓冲区大小时，系统都会将其值翻倍，并且不得小于某个值。</p><ul><li>TCP接收缓冲区最小值为256字节</li><li>TCP发送缓冲区最小值为2048字节</li></ul><p>缓冲区最小值取决于操作系统。</p><p><strong>为了保证一个TCP连接拥有足够的空闲缓冲区来处理拥塞</strong></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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//服务端，设置接收缓冲区</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUFFER_SIZE 1024</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (argc &lt;= <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s ip port buffer_size\n&quot;</span>, basename(argv[<span class="number">0</span>]));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *ip = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">int</span> port = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">addr</span>;</span></span><br><span class="line">    bzero(&amp;addr, <span class="keyword">sizeof</span>(addr));</span><br><span class="line">    addr.sin_family = AF_INET;</span><br><span class="line">    addr.sin_port = htons(port);</span><br><span class="line">    inet_pton(AF_INET, ip, &amp;addr.sin_addr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sock = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(sock &gt;= <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> recvbuf = atoi(argv[<span class="number">3</span>]);</span><br><span class="line">    <span class="keyword">int</span> len = <span class="keyword">sizeof</span>(recvbuf);</span><br><span class="line"></span><br><span class="line">    setsockopt(sock, SOL_SOCKET, SO_RCVBUF,</span><br><span class="line">               &amp;recvbuf, <span class="keyword">sizeof</span>(recvbuf));</span><br><span class="line">    getsockopt(sock, SOL_SOCKET, SO_RCVBUF,</span><br><span class="line">               &amp;recvbuf, (<span class="keyword">socklen_t</span> *)&amp;len);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;the tcp receive buffer size after setting is %d\n&quot;</span>, recvbuf);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> ret = bind(sock, (struct sockaddr *)&amp;addr,</span><br><span class="line">                   <span class="keyword">sizeof</span>(addr));</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    ret = listen(sock, <span class="number">5</span>);</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">client_addr</span>;</span></span><br><span class="line">    <span class="keyword">socklen_t</span> client_addr_len = <span class="keyword">sizeof</span>(client_addr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> connfd = accept(sock, (struct sockaddr *)&amp;client_addr,</span><br><span class="line">                        &amp;client_addr_len);</span><br><span class="line">    <span class="keyword">if</span> (connfd &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;errno is %d\n&quot;</span>, errno);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">char</span> buffer[BUFFER_SIZE];</span><br><span class="line">        <span class="built_in">memset</span>(buffer, <span class="string">&#x27;\0&#x27;</span>, BUFFER_SIZE);</span><br><span class="line">        <span class="keyword">while</span> (recv(connfd, buffer, BUFFER_SIZE - <span class="number">1</span>, <span class="number">0</span>) &gt; <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">        &#125;</span><br><span class="line">        close(connfd);</span><br><span class="line">    &#125;</span><br><span class="line">    close(sock);</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><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//客户端，设置发送缓冲区</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUFFER_SIZE 512</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (argc &lt;= <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage:%s ip_address port_number buffer_size\n&quot;</span>,</span><br><span class="line">               basename(argv[<span class="number">0</span>]));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *ip = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">int</span> port = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">server_address</span>;</span></span><br><span class="line">    bzero(&amp;server_address, <span class="keyword">sizeof</span>(server_address));</span><br><span class="line">    server_address.sin_family = AF_INET;</span><br><span class="line">    server_address.sin_port = htons(port);</span><br><span class="line">    inet_pton(AF_INET, ip, &amp;server_address.sin_addr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sock = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(sock &gt;= <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sendbuf = atoi(argv[<span class="number">3</span>]);</span><br><span class="line">    <span class="keyword">int</span> len = <span class="keyword">sizeof</span>(sendbuf);</span><br><span class="line">    setsockopt(sock, SOL_SOCKET, SO_SNDBUF,</span><br><span class="line">               &amp;sendbuf, <span class="keyword">sizeof</span>(sendbuf));</span><br><span class="line">    getsockopt(sock, SOL_SOCKET, SO_SNDBUF,</span><br><span class="line">               &amp;sendbuf, (<span class="keyword">socklen_t</span> *)&amp;len);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;the tcp send buffer size after setting is %d\n&quot;</span>, sendbuf);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (connect(sock, (struct sockaddr *)&amp;server_address,</span><br><span class="line">                <span class="keyword">sizeof</span>(server_address)) != <span class="number">-1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">char</span> buffer[BUFFER_SIZE];</span><br><span class="line">        <span class="built_in">memset</span>(buffer, <span class="string">&#x27;a&#x27;</span>, BUFFER_SIZE);</span><br><span class="line">        send(sock, buffer, BUFFER_SIZE, <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    close(sock);</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><h4 id="SO-RCVLOWAT和SO-SNDLOWAT选项"><a href="#SO-RCVLOWAT和SO-SNDLOWAT选项" class="headerlink" title="SO_RCVLOWAT和SO_SNDLOWAT选项"></a>SO_RCVLOWAT和SO_SNDLOWAT选项</h4><p>表示TCP接收缓冲区和发送缓冲区的低水位标记，一般被I/O复用系统调用用来判断socket是否可读可写。当TCP接收缓冲区中可读数据的总数大于低水位标记，I/O复用系统调用将通知应用程序可以冲对应的socket上读取数据；当TCP发送缓冲区中的空间大于低水位标记时，I/O复用系统调用将通知应用程序可以往对应的socket上写入数据。</p><p>默认情况，低水位标记为1字节。</p><h4 id="SO-LINGER选项"><a href="#SO-LINGER选项" class="headerlink" title="SO_LINGER选项"></a>SO_LINGER选项</h4><p>用于控制close系统调用在关闭TCP连接时的行为。默认情况下，当我们使用close系统调用来关闭一个socket是，close将立即返回，TCP模块扶着将该socket对用的TCP发送缓冲区残留的数据发送给对方。</p><p>设置<code>SO_LINGER</code>选项的值时，需要给setsockopt传递一个linger类型的结构体。</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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">linger</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">int</span> l_onoff;  <span class="comment">//开启(非0)还是关闭(0)该选项</span></span><br><span class="line">    <span class="keyword">int</span> l_linger; <span class="comment">//滞留时间</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>根据linger结构体中两个成员变量的不同值，close可能会产生3种行为：</p><ul><li>l_onoff 等于0。此时SO_LINGER不起作用，close用默认行为关闭socket</li><li>l_onoff不为0，l_linger等于0。此时close立即返回，TCP将丢弃被关闭socket对应的TCP发送缓冲区中残留的数据，同时给对方发送一个复位报文段。异常终止连接</li><li>l_onoff不为0，l_linger大于0。close行为取决于两个条件：<ul><li>被关闭socket是否有残留数据</li><li>该socket是阻塞还是非阻塞的<ul><li>对于阻塞：close将等待l_linger时间，直到TCP模块发送完所有残留数据并得到对方确认</li><li>对于非阻塞：close立即返回</li></ul></li></ul></li></ul><h3 id="网络信息API"><a href="#网络信息API" class="headerlink" title="网络信息API"></a>网络信息API</h3><p>socket的IP地址和端口号不便于记忆与扩展，所以使用主机名和服务名称来代替IP地址和端口号</p><h4 id="gethostbyname、gethostbyaddr"><a href="#gethostbyname、gethostbyaddr" class="headerlink" title="gethostbyname、gethostbyaddr"></a>gethostbyname、gethostbyaddr</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="comment">//根据主机名获取主机完整信息</span></span><br><span class="line"><span class="comment">//name : 目标主机名</span></span><br><span class="line"><span class="function">struct hostent *<span class="title">gethostbyname</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *name)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//根据IP地址获取主机完整信息</span></span><br><span class="line"><span class="comment">//addr : 目标主机IP地址</span></span><br><span class="line"><span class="comment">//len  : IP地址长度</span></span><br><span class="line"><span class="comment">//type : IP地址的类型(AF_INET、AF_INET6)</span></span><br><span class="line"><span class="function">struct hostent *<span class="title">gethostbyaddr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">void</span> *addr, <span class="keyword">size_t</span> len, <span class="keyword">int</span> type)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//返回值为hostent结构体</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hostent</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">char</span> *h_name;           <span class="comment">//主机名</span></span><br><span class="line">    <span class="keyword">char</span> **h_aliases;       <span class="comment">//主机别名列表</span></span><br><span class="line">    <span class="keyword">int</span> h_addrtype;         <span class="comment">//地址类型</span></span><br><span class="line">    <span class="keyword">int</span> h_length;           <span class="comment">//地址长度</span></span><br><span class="line">    <span class="keyword">char</span> **h_addr_list;     <span class="comment">//按网络字节序列出的主机IP地址列表</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="getservbyname、getservbyport"><a href="#getservbyname、getservbyport" class="headerlink" title="getservbyname、getservbyport"></a>getservbyname、getservbyport</h4><p>getservbyname函数根据名称获取某个服务的完整信息，getservbyport根据端口号获取服务的完整信息。都是通过<strong>读取/exc/services文件夹</strong>来获取服务信息。</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="comment">//name:目标服务名字</span></span><br><span class="line"><span class="comment">//port:端口号</span></span><br><span class="line"><span class="comment">//proto:服务类型tcp、udp</span></span><br><span class="line"><span class="function">struct servent *<span class="title">getservbyname</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *name, <span class="keyword">const</span> <span class="keyword">char</span> *proto)</span></span>;</span><br><span class="line"><span class="function">struct servent *<span class="title">getservbyport</span><span class="params">(<span class="keyword">int</span> port, <span class="keyword">const</span> <span class="keyword">char</span> *proto)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//返回struct servent*</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">servent</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">char</span> *s_name;     <span class="comment">//服务名称</span></span><br><span class="line">    <span class="keyword">char</span> **s_aliases; <span class="comment">//服务的别名列表，可能有多个</span></span><br><span class="line">    <span class="keyword">char</span> *s_proto;    <span class="comment">//服务类型，通常是tcp或者udp</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><em>访问daytime服务</em></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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">( <span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[] )</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">assert( argc == <span class="number">2</span> );</span><br><span class="line"><span class="keyword">char</span> *host = argv[<span class="number">1</span>];</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hostent</span>* <span class="title">hostinfo</span> =</span> gethostbyname( host );</span><br><span class="line">assert( hostinfo );</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">servent</span>* <span class="title">servinfo</span> =</span> getservbyname( <span class="string">&quot;daytime&quot;</span>, <span class="string">&quot;tcp&quot;</span> );</span><br><span class="line">assert( servinfo );</span><br><span class="line"><span class="built_in">printf</span>( <span class="string">&quot;daytime port is %d\n&quot;</span>, ntohs( servinfo-&gt;s_port ) );</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">address</span>;</span></span><br><span class="line">address.sin_family = AF_INET;</span><br><span class="line">address.sin_port = servinfo-&gt;s_port;</span><br><span class="line">address.sin_addr = *( struct in_addr* )*hostinfo-&gt;h_addr_list;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> sockfd = socket( AF_INET, SOCK_STREAM, <span class="number">0</span> );</span><br><span class="line"><span class="keyword">int</span> result = connect( sockfd, (struct sockaddr* )&amp;address, <span class="keyword">sizeof</span>( address ) );</span><br><span class="line">assert( result != <span class="number">-1</span> );</span><br><span class="line"></span><br><span class="line"><span class="keyword">char</span> buffer[<span class="number">128</span>];</span><br><span class="line">result = read( sockfd, buffer, <span class="keyword">sizeof</span>( buffer ) );</span><br><span class="line">assert( result &gt; <span class="number">0</span> );</span><br><span class="line">buffer[ result ] = <span class="string">&#x27;\0&#x27;</span>;</span><br><span class="line"><span class="built_in">printf</span>( <span class="string">&quot;the day tiem is: %s&quot;</span>, buffer );</span><br><span class="line">close( sockfd );</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><strong><em>上述四个函数属于不可重入函数(非线程安全)，可重入版本在函数名称后边加上_r即可</em></strong></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="function">struct hostent *<span class="title">gethostbyname_r</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *name)</span></span>;</span><br><span class="line"><span class="function">struct hostent *<span class="title">gethostbyaddr_r</span><span class="params">(<span class="keyword">const</span> <span class="keyword">void</span> *addr, <span class="keyword">size_t</span> len, <span class="keyword">int</span> type)</span></span>;</span><br><span class="line"><span class="function">struct servent *<span class="title">getservbyname_r</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *name, <span class="keyword">const</span> <span class="keyword">char</span> *proto)</span></span>;</span><br><span class="line"><span class="function">struct servent *<span class="title">getservbyport_r</span><span class="params">(<span class="keyword">int</span> port, <span class="keyword">const</span> <span class="keyword">char</span> *proto)</span></span>;</span><br></pre></td></tr></table></figure><h4 id="getaddrinfo"><a href="#getaddrinfo" class="headerlink" title="getaddrinfo"></a>getaddrinfo</h4><p>该函数既能通过主机名获取IP地址，也能通过服务名获得端口号。它是否可重入取决于内部调用gethostbyname、getservbyname函数是否是可重入版本。</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="comment">//hostname:可以接收主机名，也可以接收字符串表示的IP地址</span></span><br><span class="line"><span class="comment">//service:可以接收服务名，也可以接收字符串表示的十进制端口号</span></span><br><span class="line"><span class="comment">//hints:是应用程序给getaddrinfo的一个提示，以对getaddrinfo的输出进行更精准的控制，可以设置为NULL</span></span><br><span class="line"><span class="comment">//result:指向一个链表，用于存储getaddrinfo反馈的结果</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">getaddrinfo</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *hostname, <span class="keyword">const</span> <span class="keyword">char</span> *service,</span></span></span><br><span class="line"><span class="function"><span class="params">                <span class="keyword">const</span> struct addrinfo *hints, struct addrinfo **result)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">addrinfo</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">int</span> ai_flags;             <span class="comment">/* Input flags.  */</span></span><br><span class="line">    <span class="keyword">int</span> ai_family;            <span class="comment">/* 地址族  */</span></span><br><span class="line">    <span class="keyword">int</span> ai_socktype;          <span class="comment">/* 服务类型, SOCK_STREAM或SOCK_DFRAM  */</span></span><br><span class="line">    <span class="keyword">int</span> ai_protocol;          <span class="comment">/* 具体的网络协议,含义和socket系统调用的第三参数相同，设置为0  */</span></span><br><span class="line">    <span class="keyword">socklen_t</span> ai_addrlen;     <span class="comment">/* socket地址ai_addr的长度  */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr</span> *<span class="title">ai_addr</span>;</span> <span class="comment">/* 指向socket地址  */</span></span><br><span class="line">    <span class="keyword">char</span> *ai_canonname;       <span class="comment">/* 主机的别名  */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">addrinfo</span> *<span class="title">ai_next</span>;</span> <span class="comment">/* 指向下一个sockinfo结构的对象  */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>ai_flags值可以按下表的标志的按位或</strong></p><p><img src="/2021/05/20/Linux%E9%AB%98%E6%80%A7%E8%83%BD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%96%E7%A8%8B/image-20210724162958378.png" alt="image-20210724162958378"></p><p>我们使用hints参数的时候，可以设置其ai_flags、ai_family、ai_socktype和ai_protocol四个字段，其他字段必须设置为NULL。</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><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"><span class="class"><span class="keyword">struct</span> <span class="title">addrinfo</span> <span class="title">hints</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">addrinfo</span> *<span class="title">res</span>;</span></span><br><span class="line"></span><br><span class="line">bzero(&amp;hints,<span class="keyword">sizeof</span>(hints));</span><br><span class="line">hints.ai_socktype = SOCK_STREAM;</span><br><span class="line">getaddrinfo(<span class="string">&quot;ernest-laptop&quot;</span>,<span class="string">&quot;daytime&quot;</span>,&amp;hints,&amp;res);</span><br><span class="line"></span><br><span class="line"><span class="comment">//因为*res不是指向一块合法内存的，所以调用结束后要释放内存</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">freeaddrinfo</span><span class="params">(struct addrinfo* res)</span></span>;</span><br></pre></td></tr></table></figure><h4 id="getnameinfo"><a href="#getnameinfo" class="headerlink" title="getnameinfo"></a>getnameinfo</h4><p>该函数能通过socket地址通知获得以字符串表示的主机名(内部使用的gethostbyaddr函数)和服务名(内部使用getservbyport函数)。是否可重入同上</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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">getnameinfo</span><span class="params">(<span class="keyword">const</span> struct sockaddr *sockaddr,<span class="keyword">socklen_t</span> addrlen, <span class="keyword">char</span> *host,</span></span></span><br><span class="line"><span class="function"><span class="params">                <span class="keyword">socklen_t</span> hostlen, <span class="keyword">char</span> *serv,<span class="keyword">socklen_t</span> servlen, <span class="keyword">int</span> flags)</span></span>;</span><br></pre></td></tr></table></figure><p>genameinfo将返回的主机名存储在host参数指向的缓存中，将服务名存储在serv参数指向的缓存中，hostlen和servlen参数分别指定这两块缓存的长度。</p><p><strong>flag参数控制getnameinfo的行为。flag取值如下：</strong></p><p><img src="/2021/05/20/Linux%E9%AB%98%E6%80%A7%E8%83%BD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%96%E7%A8%8B/image-20210724164506566.png" alt="image-20210724164506566"></p><p><strong>getaddrinfo和getnameinfo函数成功返回0，失败返回错误码：</strong></p><p><img src="/2021/05/20/Linux%E9%AB%98%E6%80%A7%E8%83%BD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%96%E7%A8%8B/image-20210724164615865.png" alt="image-20210724164615865"></p><p><strong>Linux下strerror函数能将数值错误码errno转换成易读的字符串形式。下面函数可将上表的错误码转换成其字符串形式</strong></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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netdb.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span> *<span class="title">gai_strerror</span><span class="params">(<span class="keyword">int</span> error)</span></span>;</span><br></pre></td></tr></table></figure><h2 id="高级I-O函数"><a href="#高级I-O函数" class="headerlink" title="高级I/O函数"></a>高级I/O函数</h2><ul><li><p><input checked disabled type="checkbox">  用于创建文件描述符的函数，pipe、dup/dup2</p></li><li><p><input checked disabled type="checkbox">  用于读写数据的函数，包括readv/writev、sendfile、mmap/munmap、splice和tee</p></li><li><p><input checked disabled type="checkbox">  用于控制I/O行为和属性的函数，包括fcntl函数</p></li></ul><h3 id="pipe函数"><a href="#pipe函数" class="headerlink" title="pipe函数"></a>pipe函数</h3><p>pipe函数可用于创建一个管道，以实现进程间通信。</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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="comment">//成功返回0，失败返回-1 并设置errno</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">pipe</span><span class="params">(<span class="keyword">int</span> fd[<span class="number">2</span>])</span></span>;</span><br></pre></td></tr></table></figure><p>fd[0]和fd[1]分别构成管道两端，往fd[1]写入的数据可以从fd[0]读出，并且fd[0]只能从管道读出数据，fd[1]只能用于往管道写入数据。如果要实现双向的数据传输，应该使用两个管道。默认情况下，这一对文件描述符是阻塞的，如果我们使用read来读取一个空的管道，则将被read阻塞，直到管道有数据可读；使用write写一个满的管道也是一样。如果程序将这对fd设置为非阻塞，则read和write会有不同行为</p><p>管道内部传输的是字节流，管道容量的默认大小：65536字节</p><p>socketpair函数能够方便的创建双向管道。创建的一对文件描述符都是可读可写的。</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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/type.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="comment">//domain : AF_UNIX只能在本地使用</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">socketpair</span><span class="params">(<span class="keyword">int</span> domain, <span class="keyword">int</span> type, <span class="keyword">int</span> protocol, <span class="keyword">int</span> fd[<span class="number">2</span>])</span></span>;</span><br></pre></td></tr></table></figure><h3 id="dup函数和dup2函数"><a href="#dup函数和dup2函数" class="headerlink" title="dup函数和dup2函数"></a>dup函数和dup2函数</h3><p>这两可以把标准输入重定向到一个文件或者把标准输入重定向到一个网络连接(CGI编程)</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="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="comment">//失败返回-1 并设置errno</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dup</span><span class="params">(<span class="keyword">int</span> file_descriptor)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dup2</span><span class="params">(<span class="keyword">int</span> file_descriptor_one, <span class="keyword">int</span> file_descriptor_two)</span></span>;</span><br></pre></td></tr></table></figure><ul><li>dup：创建一个新的文件描述符，改文件描述符和原油文件描述符file_descriptor指向相同文件、管道或者网络连接，并且返回的文件描述符总是去取系统当前可用的最小整数值。</li><li>dup2：与dup类似，返回第一个不小于file_descriptor_two的整数值。</li></ul><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (argc &lt;= <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s ip port\n&quot;</span>, basename(argv[<span class="number">0</span>]));</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *ip = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">int</span> port = atoi(argv[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">server_address</span>;</span></span><br><span class="line">    bzero(&amp;server_address, <span class="keyword">sizeof</span>(server_address));</span><br><span class="line">    server_address.sin_family = AF_INET;</span><br><span class="line">    server_address.sin_port = htons(port);</span><br><span class="line">    inet_pton(AF_INET, ip, &amp;server_address.sin_addr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> sock = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    assert(sock &gt;= <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> ret = bind(sock, (struct sockaddr *)&amp;server_address,</span><br><span class="line">                   <span class="keyword">sizeof</span>(server_address));</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    ret = listen(sock, <span class="number">5</span>);</span><br><span class="line">    assert(ret != <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">client_address</span>;</span></span><br><span class="line">    <span class="keyword">socklen_t</span> client_address_len;</span><br><span class="line">    <span class="keyword">int</span> connfd = accept(sock, (struct sockaddr *)&amp;client_address, &amp;client_address_len);</span><br><span class="line">    <span class="keyword">if</span> (connfd &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;errno is: %d\n&quot;</span>, errno);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        close(STDOUT_FILENO);</span><br><span class="line">        dup(connfd);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;abcdefg\n&quot;</span>);</span><br><span class="line">        close(connfd);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    close(sock);</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><h3 id="readv函数和writev函数"><a href="#readv函数和writev函数" class="headerlink" title="readv函数和writev函数"></a>readv函数和writev函数</h3><p>readv函数</p><h3 id="sendfile"><a href="#sendfile" class="headerlink" title="sendfile"></a>sendfile</h3><h3 id="mmap函数munmap函数"><a href="#mmap函数munmap函数" class="headerlink" title="mmap函数munmap函数"></a>mmap函数munmap函数</h3><h3 id="splice函数"><a href="#splice函数" class="headerlink" title="splice函数"></a>splice函数</h3><h3 id="tee函数"><a href="#tee函数" class="headerlink" title="tee函数"></a>tee函数</h3><h3 id="fcntl函数"><a href="#fcntl函数" class="headerlink" title="fcntl函数"></a>fcntl函数</h3><h2 id="Linux服务器程序规范"><a href="#Linux服务器程序规范" class="headerlink" title="Linux服务器程序规范"></a>Linux服务器程序规范</h2><ul><li>Linux服务器程序一般以后台进程(守护进程)形式运行</li><li>通常有一套日志系统</li><li>以某个专门的非root身份运行</li><li>通常可配置</li><li>启动的时候生成一个PID文件并存入/var/run目录中</li><li>需要考虑系统资源和限制</li></ul>]]></content>
    
    
    <summary type="html">学习游双的Linux高性能服务器</summary>
    
    
    
    <category term="读书笔记" scheme="https://ethereal14.github.io/categories/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Linux 网络编程" scheme="https://ethereal14.github.io/tags/Linux-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>Linux C线程池简单实现</title>
    <link href="https://ethereal14.github.io/2021/04/11/Linux-C%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0/"/>
    <id>https://ethereal14.github.io/2021/04/11/Linux-C%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0/</id>
    <published>2021-04-11T07:37:27.000Z</published>
    <updated>2023-03-12T16:03:10.137Z</updated>
    
    <content type="html"><![CDATA[<p>​        线程池常用于高性能服务器中。为了减小线程创建、销毁时的开销，引入了池式结构。比如：内存池、数据库连接池等等。</p><p>学习线程池也只要是因为最近在学网络编程的东西。</p><h1 id="线程池结构"><a href="#线程池结构" class="headerlink" title="线程池结构"></a>线程池结构</h1><p><img src="/2021/04/11/Linux-C%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0/20171214150913376" alt="图片来自网络"></p><p>从上图可以看到线程池主要包括<strong>任务队列、线程数组</strong>、管理者线程。为了简单起见，没有加入管理者线程。</p><h1 id="调用顺序"><a href="#调用顺序" class="headerlink" title="调用顺序"></a>调用顺序</h1><p>//TODO</p><h1 id="线程池数据结构设计"><a href="#线程池数据结构设计" class="headerlink" title="线程池数据结构设计"></a>线程池数据结构设计</h1><h2 id="线程池结构定义"><a href="#线程池结构定义" class="headerlink" title="线程池结构定义"></a>线程池结构定义</h2><p>主要包括线程池的一些属性。<strong>线程池状态信息、任务队列信息、互斥锁</strong></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><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">threadpool_t</span>&#123;</span></span><br><span class="line">    <span class="keyword">pthread_mutex_t</span> lock;     <span class="comment">//用于内部工作的互斥锁</span></span><br><span class="line">    <span class="keyword">pthread_cond_t</span> notify;    <span class="comment">//线程间通知的条件变量</span></span><br><span class="line">    <span class="keyword">pthread_t</span> *threads;       <span class="comment">//线程数组</span></span><br><span class="line">    <span class="keyword">threadpool_task_t</span> *<span class="built_in">queue</span>; <span class="comment">//存储任务的数组,即任务队列</span></span><br><span class="line">    <span class="keyword">int</span> thread_count;         <span class="comment">//线程数量</span></span><br><span class="line">    <span class="keyword">int</span> queue_size;           <span class="comment">//任务队列大小</span></span><br><span class="line">    <span class="keyword">int</span> head;                 <span class="comment">//任务队列中首个任务位置（注：任务队列中所有任务都是未开始运行的）</span></span><br><span class="line">    <span class="keyword">int</span> tail;                 <span class="comment">//任务队列中最后一个任务的下一个位置（注：队列以数组存储，head 和 tail 指示队列位置）</span></span><br><span class="line">    <span class="keyword">int</span> count;                <span class="comment">//任务队列里的任务数量，即等待运行的任务数</span></span><br><span class="line">    <span class="keyword">int</span> shutdown;             <span class="comment">//表示线程池是否关闭</span></span><br><span class="line">    <span class="keyword">int</span> started;              <span class="comment">//开始的线程数   </span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="任务队列结构定义"><a href="#任务队列结构定义" class="headerlink" title="任务队列结构定义"></a>任务队列结构定义</h2><p>可以放置多种不同任务函数的函数指针，参数为*<em>void**</em>型</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">void</span> (*function)(<span class="keyword">void</span> *);<span class="comment">//函数指针，参数为void*。任意线程函数</span></span><br><span class="line">    <span class="keyword">void</span> *argument;<span class="comment">//线程函数参数</span></span><br><span class="line">&#125; <span class="keyword">threadpool_task_t</span>;</span><br></pre></td></tr></table></figure><h2 id="其他一些枚举类型"><a href="#其他一些枚举类型" class="headerlink" title="其他一些枚举类型"></a>其他一些枚举类型</h2><h3 id="错误码"><a href="#错误码" class="headerlink" title="错误码"></a>错误码</h3><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><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">enum</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    threadpool_invalid = <span class="number">-1</span>,</span><br><span class="line">    threadpool_lock_failure = <span class="number">-2</span>,</span><br><span class="line">    threadpool_queue_full = <span class="number">-3</span>,</span><br><span class="line">    threadpool_shutdown = <span class="number">-4</span>,</span><br><span class="line">    threadpool_thread_failure = <span class="number">-5</span></span><br><span class="line">&#125; <span class="keyword">threadpool_terror_t</span>;</span><br></pre></td></tr></table></figure><h3 id="线程池关闭方式"><a href="#线程池关闭方式" class="headerlink" title="线程池关闭方式"></a>线程池关闭方式</h3><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="keyword">typedef</span> <span class="class"><span class="keyword">enum</span> &#123;</span></span><br><span class="line">    immediate_shutdown = <span class="number">1</span>, <span class="comment">//自动关闭</span></span><br><span class="line">    graceful_shutdown  = <span class="number">2</span><span class="comment">//立即关闭</span></span><br><span class="line">&#125; <span class="keyword">threadpool_shutdown_t</span>;</span><br></pre></td></tr></table></figure><h3 id="线程池销毁的枚举"><a href="#线程池销毁的枚举" class="headerlink" title="线程池销毁的枚举"></a>线程池销毁的枚举</h3><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="keyword">typedef</span> <span class="class"><span class="keyword">enum</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    threadpool_graceful = <span class="number">1</span></span><br><span class="line">&#125; <span class="keyword">threadpool_destroy_flags_t</span>;</span><br></pre></td></tr></table></figure><h1 id="线程池API设计"><a href="#线程池API设计" class="headerlink" title="线程池API设计"></a>线程池API设计</h1><p>线程池对外开放了三个API：</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @function threadpool_create</span></span><br><span class="line"><span class="comment"> * @brief 创建线程池</span></span><br><span class="line"><span class="comment"> * @param thread_count 工作线程数量</span></span><br><span class="line"><span class="comment"> * @param thread_queue 任务队列大小</span></span><br><span class="line"><span class="comment"> * @param flags    未使用的参数</span></span><br><span class="line"><span class="comment"> * @return 返回一个新创建的线程池或者NULL</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">threadpool_t</span> *<span class="title">threadpool_create</span><span class="params">(<span class="keyword">int</span> thread_count, <span class="keyword">int</span> queue_size, <span class="keyword">int</span> flags)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @function threadpool_add</span></span><br><span class="line"><span class="comment"> * @brief 添加新任务到线程池队列中</span></span><br><span class="line"><span class="comment"> * @param pool 线程池指针</span></span><br><span class="line"><span class="comment"> * @param routine 函数指针</span></span><br><span class="line"><span class="comment"> * @param arg       传入函数的参数</span></span><br><span class="line"><span class="comment"> * @param flags 未使用的参数</span></span><br><span class="line"><span class="comment"> * @return 成功返回0，失败返回错误码</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">threadpool_add</span><span class="params">(<span class="keyword">threadpool_t</span> *pool, <span class="keyword">void</span> (*routine)(<span class="keyword">void</span> *),<span class="keyword">void</span> *arg, <span class="keyword">int</span> flags)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @function threadpool_destroy</span></span><br><span class="line"><span class="comment"> * @brief 停止并且摧毁线程池</span></span><br><span class="line"><span class="comment"> * @param pool 线程池指针</span></span><br><span class="line"><span class="comment"> * @param flags 指定关闭方式</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">threadpool_destroy</span><span class="params">(<span class="keyword">threadpool_t</span> *pool, <span class="keyword">int</span> flags)</span></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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> *<span class="title">threadpool_thread</span><span class="params">(<span class="keyword">void</span> *threadpool)</span></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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">threadpool_free</span><span class="params">(<span class="keyword">threadpool_t</span> *pool)</span></span>;</span><br></pre></td></tr></table></figure><h2 id="创建线程池"><a href="#创建线程池" class="headerlink" title="创建线程池"></a>创建线程池</h2><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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">threadpool_t</span> *<span class="title">threadpool_create</span><span class="params">(<span class="keyword">int</span> thread_count, <span class="keyword">int</span> queue_size, <span class="keyword">int</span> flags)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//对传入参数进行判断，MAX_THREADS、MAX_QUEUE为宏定义，自行定义</span></span><br><span class="line">    <span class="keyword">if</span> (thread_count &lt;= <span class="number">0</span> || thread_count &gt; MAX_THREADS || </span><br><span class="line">        queue_size &lt;= <span class="number">0</span> || queue_size &gt; MAX_QUEUE) </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</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="keyword">threadpool_t</span> *pool;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//动态申请线程池空间，失败goto err</span></span><br><span class="line">    <span class="keyword">if</span> ((pool = (<span class="keyword">threadpool_t</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">threadpool_t</span>))) == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">goto</span> err;</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">    pool-&gt;thread_count = <span class="number">0</span>;</span><br><span class="line">    pool-&gt;queue_size = queue_size;</span><br><span class="line">    pool-&gt;head = pool-&gt;tail = pool-&gt;count = <span class="number">0</span>;</span><br><span class="line">    pool-&gt;shutdown = pool-&gt;started = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//线程数组动态申请</span></span><br><span class="line">    pool-&gt;threads = (<span class="keyword">pthread_t</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">pthread_t</span>) * thread_count);</span><br><span class="line">    <span class="comment">//任务队列动态申请</span></span><br><span class="line">    pool-&gt;<span class="built_in">queue</span> = (<span class="keyword">threadpool_task_t</span> *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">threadpool_task_t</span>) * queue_size);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//初始化互斥锁、条件变量并判断线程数组、任务队列等是否申请(初始化成功)</span></span><br><span class="line">    <span class="keyword">if</span> ((pthread_mutex_init(&amp;pool-&gt;lock, <span class="literal">NULL</span>) != <span class="number">0</span>) ||</span><br><span class="line">        (pthread_cond_init(&amp;pool-&gt;notify, <span class="literal">NULL</span>) != <span class="number">0</span>) ||</span><br><span class="line">        (pool-&gt;threads == <span class="literal">NULL</span>) || (pool-&gt;<span class="built_in">queue</span> == <span class="literal">NULL</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">goto</span> err;</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="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; thread_count; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (pthread_create(&amp;pool-&gt;threads[i], <span class="literal">NULL</span>, threadpool_thread, (<span class="keyword">void</span> *)pool) != <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            threadpool_destroy(pool, <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        pool-&gt;thread_count++;<span class="comment">//每成功创建一个线程，工作线程数量++</span></span><br><span class="line">        pool-&gt;started++;<span class="comment">//每运行一个线程，运行中线程数量++</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> pool;</span><br><span class="line"></span><br><span class="line">err:</span><br><span class="line">    <span class="keyword">if</span> (pool)</span><br><span class="line">    &#123;</span><br><span class="line">        threadpool_free(pool);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">threadpool_add</span><span class="params">(<span class="keyword">threadpool_t</span> *pool, <span class="keyword">void</span> (*function)(<span class="keyword">void</span> *), <span class="keyword">void</span> *argument, <span class="keyword">int</span> flags)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> err = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">int</span> next;</span><br><span class="line"><span class="comment">//参数判断</span></span><br><span class="line">    <span class="keyword">if</span> (pool == <span class="literal">NULL</span> || function == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> threadpool_invalid;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">//对资源进行上锁。若上锁失败，会阻塞。</span></span><br><span class="line">    <span class="keyword">if</span> (pthread_mutex_lock(&amp;(pool-&gt;lock)) != <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> threadpool_lock_failure;</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">    next = pool-&gt;tail + <span class="number">1</span>;</span><br><span class="line">    <span class="comment">//判断next到没到任务队列的上限，没有就next = next</span></span><br><span class="line">    next = (next == pool-&gt;queue_size) ? <span class="number">0</span> : next;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//此处使用do &#123;...&#125;while(0)结构是为了保证至少运行一次。如果有异常，直接break掉，不运行后边的语句</span></span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//判断线程池中任务数量是否小于任务队列上限</span></span><br><span class="line">        <span class="keyword">if</span> (pool-&gt;count == pool-&gt;queue_size)</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_queue_full;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//添加任务到任务队列。queue实际大小是0~255，而next是从1开始，1~256</span></span><br><span class="line">        pool-&gt;<span class="built_in">queue</span>[pool-&gt;tail].function = function;</span><br><span class="line">        pool-&gt;<span class="built_in">queue</span>[pool-&gt;tail].argument = argument;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//这句就相当于pool-&gt;tail++</span></span><br><span class="line">        pool-&gt;tail = next;</span><br><span class="line">        <span class="comment">//任务数量++</span></span><br><span class="line">        pool-&gt;count += <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//条件变量。任务添加到队列以后，发出信号通知空闲线程取任务。</span></span><br><span class="line">        <span class="keyword">if</span> (pthread_cond_signal(&amp;(pool-&gt;notify)) != <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_lock_failure;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">while</span> (<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//释放资源</span></span><br><span class="line">    <span class="keyword">if</span> (pthread_mutex_unlock(&amp;(pool-&gt;lock)) != <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        err = threadpool_lock_failure;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="线程池销毁"><a href="#线程池销毁" class="headerlink" title="线程池销毁"></a>线程池销毁</h2><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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">threadpool_destroy</span><span class="params">(<span class="keyword">threadpool_t</span> *pool, <span class="keyword">int</span> flags)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> i, err = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pool == <span class="literal">NULL</span>)</span><br><span class="line">        <span class="keyword">return</span> threadpool_invalid;</span><br><span class="line">    <span class="comment">//对资源进行上锁(取得互斥锁资源)</span></span><br><span class="line">    <span class="keyword">if</span> (pthread_mutex_lock(&amp;(pool-&gt;lock)) != <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">return</span> threadpool_lock_failure;</span><br><span class="line">    </span><br><span class="line"><span class="comment">//此处使用do &#123;...&#125;while(0)结构是为了保证至少运行一次。如果有异常，直接break掉，不运行后边的语句</span></span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//判断是否已经关闭了线程池</span></span><br><span class="line">        <span class="keyword">if</span> (pool-&gt;shutdown)</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_shutdown;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//指定线程池关闭方式;graceful_shutdown为自动关闭，即等待所有线程完成任务后退出</span></span><br><span class="line">        <span class="comment">//immediate_shutdown，立即退出，不等待</span></span><br><span class="line">        pool-&gt;shutdown = (flags &amp; threadpool_graceful) ? graceful_shutdown : immediate_shutdown;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//唤醒所有因条件变脸阻塞的线程，并释放互斥锁</span></span><br><span class="line">        <span class="keyword">if</span> ((pthread_cond_broadcast(&amp;(pool-&gt;notify)) != <span class="number">0</span>) || (pthread_mutex_unlock(&amp;(pool-&gt;lock)) != <span class="number">0</span>))</span><br><span class="line">        &#123;</span><br><span class="line">            err = threadpool_lock_failure;</span><br><span class="line">            <span class="keyword">break</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="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; pool-&gt;thread_count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (pthread_join(pool-&gt;threads[i], <span class="literal">NULL</span>) != <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                err = threadpool_thread_failure;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">while</span> (<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!err)</span><br><span class="line">    &#123;</span><br><span class="line">        threadpool_free(pool);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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><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="function"><span class="keyword">int</span> <span class="title">threadpool_free</span><span class="params">(<span class="keyword">threadpool_t</span> *pool)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//判断参数是否合法</span></span><br><span class="line">    <span class="keyword">if</span> (pool == <span class="literal">NULL</span> || pool-&gt;started &gt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//释放互斥锁、条件变量、malloc出的条件队列、线程数组等</span></span><br><span class="line">    <span class="keyword">if</span> (pool-&gt;threads)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">free</span>(pool-&gt;threads);</span><br><span class="line">        <span class="built_in">free</span>(pool-&gt;<span class="built_in">queue</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//以防万一，加锁后再destroy。不写应该没有啥问题</span></span><br><span class="line">        pthread_mutex_lock(&amp;(pool-&gt;lock));</span><br><span class="line">        pthread_mutex_destroy(&amp;(pool-&gt;lock));</span><br><span class="line">        pthread_cond_destroy(&amp;(pool-&gt;notify));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">free</span>(pool);</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><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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> *<span class="title">threadpool_thread</span><span class="params">(<span class="keyword">void</span> *threadpool)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">threadpool_t</span> *pool = (<span class="keyword">threadpool_t</span> *)threadpool;</span><br><span class="line">    <span class="keyword">threadpool_task_t</span> task;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (;;)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">/* 取得互斥资源 */</span></span><br><span class="line">        pthread_mutex_lock(&amp;(pool-&gt;lock));</span><br><span class="line"><span class="comment">//使用while是为了在唤醒时重新检查条件</span></span><br><span class="line">        <span class="keyword">while</span> ((pool-&gt;count == <span class="number">0</span>) &amp;&amp; (!pool-&gt;shutdown))</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">//任务队列为空，且线程池没有关闭时，阻塞在这里。</span></span><br><span class="line">            pthread_cond_wait(&amp;(pool-&gt;notify), &amp;(pool-&gt;lock));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//判断线程池关闭方式，immediate_shutdown时，立即break，并退出</span></span><br><span class="line">        <span class="comment">//graceful_shutdown时，要等待线程池中任务被全部取走，即count == 0时</span></span><br><span class="line">        <span class="keyword">if</span> ((pool-&gt;shutdown == immediate_shutdown) || ((pool-&gt;shutdown == graceful_shutdown) &amp;&amp; (pool-&gt;count == <span class="number">0</span>)))</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">break</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">        task.function = pool-&gt;<span class="built_in">queue</span>[pool-&gt;head].function;</span><br><span class="line">        task.argument = pool-&gt;<span class="built_in">queue</span>[pool-&gt;head].argument;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//更新head、cout</span></span><br><span class="line">        pool-&gt;head += <span class="number">1</span>;</span><br><span class="line">        pool-&gt;head = (pool-&gt;head == pool-&gt;queue_size) ? <span class="number">0</span> : pool-&gt;head;</span><br><span class="line">        pool-&gt;count -= <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//释放互斥资源</span></span><br><span class="line">        pthread_mutex_unlock(&amp;(pool-&gt;lock));</span><br><span class="line"></span><br><span class="line">        <span class="comment">//运行任务</span></span><br><span class="line">        (*(task.function))(task.argument);</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">    pool-&gt;started--;</span><br><span class="line"></span><br><span class="line">    pthread_mutex_unlock(&amp;(pool-&gt;lock));</span><br><span class="line">    pthread_exit(<span class="literal">NULL</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</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 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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;threadpool.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;assert.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> THREAD 32</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> QUEUE 256</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> tasks = <span class="number">0</span>, done = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">pthread_mutex_t</span> lock;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dummy_task</span><span class="params">(<span class="keyword">void</span> *arg)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    usleep(<span class="number">10000</span>);</span><br><span class="line">    pthread_mutex_lock(&amp;lock);</span><br><span class="line">    <span class="comment">/* 记录成功完成的任务数 */</span></span><br><span class="line">    done++;</span><br><span class="line"></span><br><span class="line">    pthread_mutex_unlock(&amp;lock);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">threadpool_t</span> *pool;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 初始化互斥锁 */</span></span><br><span class="line">    pthread_mutex_init(&amp;lock, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 断言线程池创建成功 */</span></span><br><span class="line">    assert((pool = threadpool_create(THREAD, QUEUE, <span class="number">0</span>)) != <span class="literal">NULL</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Pool started with %d threads and queue size of %d\n&quot;</span>, THREAD, QUEUE);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 只要任务队列还没满，就一直添加 */</span></span><br><span class="line">    <span class="keyword">while</span> (threadpool_add(pool, &amp;dummy_task, <span class="literal">NULL</span>, <span class="number">0</span>) == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        pthread_mutex_lock(&amp;lock);</span><br><span class="line">        tasks++;</span><br><span class="line">        pthread_mutex_unlock(&amp;lock);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;added %d tasks\n&quot;</span>, tasks);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* 不断检查任务数是否完成一半以上，没有则继续休眠 */</span></span><br><span class="line">    <span class="keyword">while</span> ((tasks / <span class="number">2</span>) &gt; done)</span><br><span class="line">    &#123;</span><br><span class="line">        usleep(<span class="number">10000</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/* 这时候销毁线程池,0 代表 immediate_shutdown 1 代表 graceful_shutdown*/</span></span><br><span class="line">    assert(threadpool_destroy(pool, <span class="number">1</span>) == <span class="number">0</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;did %d tasks\n&quot;</span>, done);</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><h1 id="pthread库一些函数"><a href="#pthread库一些函数" class="headerlink" title="pthread库一些函数"></a>pthread库一些函数</h1><h3 id="创建线程"><a href="#创建线程" class="headerlink" title="创建线程"></a>创建线程</h3><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><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="comment">/**</span></span><br><span class="line"><span class="comment"> * @function pthread_create</span></span><br><span class="line"><span class="comment"> * @brief 创建线程</span></span><br><span class="line"><span class="comment"> * @param thread 线程标识符地址</span></span><br><span class="line"><span class="comment"> * @param attr 线程属性结构体地址</span></span><br><span class="line"><span class="comment"> * @param start_routine 线程函数的入口地址</span></span><br><span class="line"><span class="comment"> * @param arg传给线程函数的参数</span></span><br><span class="line"><span class="comment"> * @return 成功 返回0；失败 返回 非0 </span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">pthread_create</span><span class="params">(<span class="keyword">pthread_t</span> *thread,<span class="keyword">const</span> <span class="keyword">pthread_attr_t</span> *attr, <span class="keyword">void</span> *(*start_routine)(<span class="keyword">void</span> *),<span class="keyword">void</span> *arg)</span></span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="初始化互斥锁"><a href="#初始化互斥锁" class="headerlink" title="初始化互斥锁"></a>初始化互斥锁</h3><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="function"><span class="keyword">int</span> <span class="title">pthread_mutex_init</span><span class="params">(<span class="keyword">pthread_mutex_t</span> *__mutex, <span class="keyword">const</span> <span class="keyword">pthread_mutexattr_t</span> *__mutexattr)</span></span></span><br></pre></td></tr></table></figure><h3 id="初始化条件变量"><a href="#初始化条件变量" class="headerlink" title="初始化条件变量"></a>初始化条件变量</h3><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="function"><span class="keyword">int</span> <span class="title">pthread_cond_init</span><span class="params">(<span class="keyword">pthread_cond_t</span> *__restrict__ __cond, <span class="keyword">const</span> <span class="keyword">pthread_condattr_t</span> *__restrict__ __cond_attr)</span></span></span><br></pre></td></tr></table></figure><p>//TODO</p>]]></content>
    
    
    <summary type="html">在学习网络编程时，不少书中提到的线程池。决定找个开源库参考着学习一下。</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="Linux" scheme="https://ethereal14.github.io/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>嵌入式面试题总结</title>
    <link href="https://ethereal14.github.io/2021/03/06/%E5%B5%8C%E5%85%A5%E5%BC%8F%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93/"/>
    <id>https://ethereal14.github.io/2021/03/06/%E5%B5%8C%E5%85%A5%E5%BC%8F%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93/</id>
    <published>2021-03-06T07:17:35.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    <content type="html"><![CDATA[<h1 id="C-C-题目"><a href="#C-C-题目" class="headerlink" title="C/C++题目"></a>C/C++题目</h1><h2 id="static关键字："><a href="#static关键字：" class="headerlink" title="static关键字："></a>static关键字：</h2><ol><li><p>static修饰局部变量：使其变为静态储存方式(静态数据区)，在函数执行完之后不会被释放，继续背包留在内存中</p></li><li><p>static修饰全局变量：使其只在本文件有效，其他文件不可连接或引用该变量</p></li><li><p>static修饰函数：函数只在本文件有效，对其他文件是不可见的。静态函数好处：不用担心与其他文件的同名函数产生干扰，是对函数的一种保护机制</p></li></ol><p>​    </p><h2 id="const关键字"><a href="#const关键字" class="headerlink" title="const关键字"></a>const关键字</h2><ol><li><p>const修饰常量：定义时就初始化，以后不能更改</p></li><li><p>const修饰形参：在该函数里不能改变</p></li><li><p>const修饰类成员函数：该函数对成员变量只能进行只读操作。即：const类成员函数不能修改成员变量的值。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> a = <span class="number">10</span>;    <span class="comment">//a是一个常整形数,10不能修改</span></span><br><span class="line"><span class="keyword">int</span> <span class="keyword">const</span> a = <span class="number">10</span>;<span class="comment">//a是一个常整形数,10不能修改</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> *a = <span class="number">10</span>;<span class="comment">//a是一个指向常整型的指针，指针可以修改(a可以改)，整型数(*a、10)不能修改</span></span><br><span class="line"><span class="keyword">int</span> *<span class="keyword">const</span> a = <span class="number">10</span>;<span class="comment">//a是一个指向整形的常指针，指针不能修改(a不可以改)，整型数(*a、10)可以修改</span></span><br><span class="line"><span class="keyword">int</span> <span class="keyword">const</span> *a <span class="keyword">const</span>; <span class="comment">//a是一个指向常整型数的常指针，指针、整型数都不能修改</span></span><br></pre></td></tr></table></figure></li></ol><p>​    </p><h2 id="代码编译到可执行文件的过程"><a href="#代码编译到可执行文件的过程" class="headerlink" title="代码编译到可执行文件的过程"></a>代码编译到可执行文件的过程</h2><ol><li><p>预编译：hello.c —–&gt; hello.i</p></li><li><p>编译：hello.i —–&gt; hello.s</p></li><li><p>汇编：hello.s —–&gt; hello.o</p></li><li><p>链接：hello.o —–&gt; hello可执行文件</p></li></ol><p><strong>其中：.c   .i  .s 文件为文本文件</strong></p><p><strong>.o 与可执行文件为二进制文件</strong></p><figure class="highlight plain"><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">graph LR</span><br><span class="line">A[hello.c] -- 预处理器cpp --&gt; B[hello.i]</span><br><span class="line">B[hello.i] -- 编译器ccl --&gt; C[hello.s]</span><br><span class="line">C[hello.s] -- 汇编器as --&gt; D[hello.o]</span><br><span class="line">E[printf.o] --包含--&gt; D[hello.o]</span><br><span class="line">D[hello.o] -- 链接器ld --&gt; F[hello可执行文件]</span><br></pre></td></tr></table></figure><h2 id="内存四区、什么变量分别存储在什么区域，堆上还是栈上"><a href="#内存四区、什么变量分别存储在什么区域，堆上还是栈上" class="headerlink" title="内存四区、什么变量分别存储在什么区域，堆上还是栈上"></a>内存四区、什么变量分别存储在什么区域，堆上还是栈上</h2><ul><li><p>栈区：函数的参数值、返回值、局部变量等</p></li><li><p>堆区：用于动态内存分配</p></li><li><p>全局区(静态区)：全局变量、静态变量、常量等。全局区=未初始化数据(bss) + 初始化数据(data) + 文字常量区(data)</p></li><li><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><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="keyword">int</span> a0=<span class="number">1</span>;<span class="comment">//全局初始化变量。生命周期为整个程序运行期间；作用域为所有文件；存储位置为data段</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> a1;<span class="comment">//全局静态未初始化变量。生命周期为整个程序运行期间；作用域为当前文件；存储位置为bss段</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">static</span> a2=<span class="number">0</span>;<span class="comment">//全局静态变量</span></span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">int</span> a3;<span class="comment">//全局初始化变量。</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">fun</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> a4;<span class="comment">//局部变量。生命周期为fun函数执行期间。作用域为fun函数内部；存储位置为栈区</span></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> a5;<span class="comment">//局部易变变量</span></span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><p><strong>堆区大还是栈区大</strong></p><p>一般是堆区较大。</p><p>栈区：高地址-&gt;低地址，向下增长</p><p>堆区：低地址-&gt;高地址，向上增长</p><h2 id="extern-“C”的作用"><a href="#extern-“C”的作用" class="headerlink" title="extern “C”的作用"></a>extern “C”的作用</h2><p>可以在c++中使用c的以编译好的函数模块。</p><p>extern “C”在连接阶段起作用。</p><h1 id="进程与线程"><a href="#进程与线程" class="headerlink" title="进程与线程"></a>进程与线程</h1><h2 id="进程、线程是什么，有什么区别"><a href="#进程、线程是什么，有什么区别" class="headerlink" title="进程、线程是什么，有什么区别"></a>进程、线程是什么，有什么区别</h2><ul><li>进程：资源分配的基本单位</li><li>线程：CPU调度和分配的基本单位(程序执行的最小单位)</li></ul><p>单核CPU，同一时间，只有一个进程在运行，并发执行，是因为切换速度过快</p><p>多核CPU，同一时间，可以执行多个进程</p><h2 id="多线程、多进程优缺点"><a href="#多线程、多进程优缺点" class="headerlink" title="多线程、多进程优缺点"></a>多线程、多进程优缺点</h2><ol><li>一个进程死了不影响其他进程；一个线程崩溃可能会影响它本身所处的进程。</li><li>创建多进程的花销大于创建多线程。</li><li>多进程通信因为需要跨越进程边界，不适合大量数据的传输，适合少量或密集数据传输。多线程无需跨越进程边界，适合线程间大量数据传输。并且多线程可以共享同一进程的共享内存和变量</li></ol><h2 id="多进程、多线程同步-通信-的方法"><a href="#多进程、多线程同步-通信-的方法" class="headerlink" title="多进程、多线程同步(通信)的方法"></a>多进程、多线程同步(通信)的方法</h2><ul><li>进程间通信：<ol><li>有名管道、无名管道</li><li>信号</li><li>共享内存</li><li>消息队列</li><li>信号量</li><li>socket</li></ol></li><li>线程通信：<ol><li>信号量</li><li>读写锁</li><li>条件变量</li><li>互斥锁</li><li>自旋锁</li></ol></li></ul><h2 id="什么时候用进程、什么时候用线程"><a href="#什么时候用进程、什么时候用线程" class="headerlink" title="什么时候用进程、什么时候用线程"></a>什么时候用进程、什么时候用线程</h2><ol><li>创建和销毁较频繁使用线程，因为创建进程开销大</li><li>需要传输大量数据使用线程，因为多线程切换快，不需要跨越进程边界</li><li>安全稳定选进程，快速频繁选线程</li></ol><h2 id="进程线程的状态切换"><a href="#进程线程的状态切换" class="headerlink" title="进程线程的状态切换"></a>进程线程的状态切换</h2><ol><li>就绪状态：进程已获得除CPU外的所有资源，只等待CPU时的状态。一个系统会将多个处于就绪状态的进程排成一个就绪队列</li><li>执行状态：进程已获得CPU使用权，正在执行。单核处理器系统中，处于执行状态的进程只有一个；多核处理器，有多个处于执行状态的进程</li><li>阻塞状态：正在执行的进程由于某种原因而暂时无法继续执行。通常导致进程阻塞的典型事件有：请求I/O，申请缓冲空间等。一般，处于阻塞状态的进程会排成一个队列。</li></ol><p><img src="/2021/03/06/%E5%B5%8C%E5%85%A5%E5%BC%8F%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93/image-20210315203009813.png" alt="image-20210315203009813"></p><h2 id="父进程、子进程"><a href="#父进程、子进程" class="headerlink" title="父进程、子进程"></a>父进程、子进程</h2><p>父进程调用fork()函数后，克隆出一个子进程，子进程和父进程拥有相同内容的代码段、数据段和用户堆栈。父进程和子进程谁先执行不一定，看CPU。所以我们一般会设置父进程等待子进程执行完毕。</p><h2 id="什么是上下文切换"><a href="#什么是上下文切换" class="headerlink" title="什么是上下文切换"></a>什么是上下文切换</h2><ul><li>进程上下文：一个进程在执行的时候，CPU的所有寄存器中的值、进程的状态以及堆栈中的内容，当内核需要切换到另一个进程是，他需要保存当前进程的所有状态、即保存当前进程的进程上下文，以便再次执行该进程时，能够恢复切换时的状态，继续执行。</li><li>中断上下文：由于触发信号，导致CPU中断当前进程，转而去执行另外的程序。那么当前进程的所有资源要保存，比如堆栈和指针。保存后转而去执行中断处理程序，快读执行完毕返回，返回后恢复上一个进程的资源，继续执行。</li></ul><h1 id="网络编程"><a href="#网络编程" class="headerlink" title="网络编程"></a>网络编程</h1><h2 id="TCP、UDP区别"><a href="#TCP、UDP区别" class="headerlink" title="TCP、UDP区别"></a>TCP、UDP区别</h2><ul><li><p>TCP—传输控制协议。面向连接的可靠的字节流服务。当客户端和服务端彼此交换数据前，必须在双方之间建立一个TCP连接，之后才能传输数据。</p></li><li><p>UDP–用户数据报协议。是一个简单的面向数据报的运输层协议。UDP不提供可靠性，只是把应用程序传给IP层的数据报发送出去，但是并不能保证他们能到达目的地。</p><ol><li><p>TCP面向连接、UDP面向无连接。</p></li><li><p>UDP程序结构简单</p></li><li><p>TCP面向字节流，UDP基于数据报</p></li><li><p>TCP保证数据正确性，UDP可能丢包</p></li><li><p>TCP保证数据顺序到达，UDP不保证</p></li></ol></li></ul><h2 id="TCP、UDP优缺点"><a href="#TCP、UDP优缺点" class="headerlink" title="TCP、UDP优缺点"></a>TCP、UDP优缺点</h2><table><thead><tr><th>协议</th><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>TCP</td><td>可靠稳定</td><td>慢、效率低，占用系统资源较高，易被攻击</td></tr><tr><td>UDP</td><td>快、比TCP稍安全</td><td>不可靠、不稳定</td></tr></tbody></table><h2 id="TCP、UDP适用场景"><a href="#TCP、UDP适用场景" class="headerlink" title="TCP、UDP适用场景"></a>TCP、UDP适用场景</h2><p>TCP：传输一些对信号完整性，信号质量有要求的信息。</p><p>UDP：对网络通信质量要求不高，要求通信速度快的场景。</p><h2 id="TCP为什么可靠"><a href="#TCP为什么可靠" class="headerlink" title="TCP为什么可靠"></a>TCP为什么可靠</h2><p>因为TCP传输的数据满足3个条件：不丢失、不重复、按顺序到达</p><h2 id="OSI典型模型网络模型"><a href="#OSI典型模型网络模型" class="headerlink" title="OSI典型模型网络模型"></a>OSI典型模型网络模型</h2><table style="text-align:center">   <tr>      <td>OSI模型</td>      <td>linux tcpip模型</td>      <td>常用协议</td>      <td>网络设备</td>   </tr>   <tr>      <td>应用层</td>      <td rowspan="3">应用层</td>      <td rowspan="3">telnet/DHCP/TFTP/FTP/MQTT/NFS/DNS/FTP/SNMP</td>      <td rowspan="3"></td>   </tr>   <tr>      <td>表示层</td>   </tr>   <tr>      <td>会话层</td>   </tr>   <tr>      <td>传输层</td>      <td>传输层</td>      <td>TCP/UDP</td>      <td>四层交换机</td>   </tr>   <tr>      <td>网络层</td>      <td>网络层</td>      <td>IP/ICMP/IGMP/ARP</td>      <td>路由器，三层交换机</td>   </tr>   <tr>      <td>数据链路层</td>      <td rowspan="2">网络接口层</td>      <td rowspan="2">Ethernet/PPP/PPPoE</td>      <td>交换机（二层交换机），网桥，网卡（一半物理层，一半链路层）</td>   </tr>   <tr>      <td>物理层</td>      <td>中继器、集线器</td>   </tr></table><h1 id="单片机、RTOS"><a href="#单片机、RTOS" class="headerlink" title="单片机、RTOS"></a>单片机、RTOS</h1><h1 id="Linux"><a href="#Linux" class="headerlink" title="Linux"></a>Linux</h1>]]></content>
    
    
    <summary type="html">各处收集的面试题</summary>
    
    
    
    <category term="笔面试相关" scheme="https://ethereal14.github.io/categories/%E7%AC%94%E9%9D%A2%E8%AF%95%E7%9B%B8%E5%85%B3/"/>
    
    
    <category term="面试" scheme="https://ethereal14.github.io/tags/%E9%9D%A2%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>Linux系统编程</title>
    <link href="https://ethereal14.github.io/2021/03/04/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <id>https://ethereal14.github.io/2021/03/04/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/</id>
    <published>2021-03-04T11:09:04.000Z</published>
    <updated>2023-03-12T16:03:10.137Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Shell脚本"><a href="#Shell脚本" class="headerlink" title="Shell脚本"></a>Shell脚本</h1><p>TODO</p><h1 id="系统调用"><a href="#系统调用" class="headerlink" title="系统调用"></a>系统调用</h1><p>TODO</p><h1 id="进程"><a href="#进程" class="headerlink" title="进程"></a>进程</h1><p>TODO</p><h1 id="信号"><a href="#信号" class="headerlink" title="信号"></a>信号</h1><h2 id="进程间通信概述"><a href="#进程间通信概述" class="headerlink" title="进程间通信概述"></a>进程间通信概述</h2><h3 id="进程间通信-IPC-："><a href="#进程间通信-IPC-：" class="headerlink" title="进程间通信(IPC)："></a>进程间通信(IPC)：</h3><p>​        进程是一个独立的资源分配单元，不同进程（这里所说的进程通常指的是用户进程）之间的资源是独立的， 没有                关联，不能在一个进程中直接访问另一个进程的资源（例如打开的文件描述符）。 </p><p>​        进程不是孤立的，不同的进程需要进行信息的交互和状态的传递等，因此需要进程间通信。</p><h3 id="进程间通信功能："><a href="#进程间通信功能：" class="headerlink" title="进程间通信功能："></a>进程间通信功能：</h3><p>​        <strong>数据传输：</strong>一个进程需要将它的数据发送给另一个进程。 </p><p>​        <strong>资源共享：</strong>多个进程之间共享同样的资源。 </p><p>​        <strong>通知事件：</strong>一个进程需要向另一个或一组进程发送消息，通知它们发生了某种事件。 </p><p>​        <strong>进程控制：</strong>有些进程希望完全控制另一个进程的执行（如 Debug 进程），此时控制进程希望能够拦截另一个进程 </p><p>​                            的所有操作，并能够及时知道它的状态改变。</p><h3 id="Linux操作系统支持的主要进程间通信的通信机制"><a href="#Linux操作系统支持的主要进程间通信的通信机制" class="headerlink" title="Linux操作系统支持的主要进程间通信的通信机制"></a>Linux操作系统支持的主要进程间通信的通信机制</h3><p><img src="/2021/03/04/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/1614856745682.png" alt="1614856745682"></p><h3 id="进程间通信的实质："><a href="#进程间通信的实质：" class="headerlink" title="进程间通信的实质："></a>进程间通信的实质：</h3><p>系统只要创建一个进程，就会给当前进程分配4G的虚拟内存(32位操作系统)。0<del>3G为用户空间，3</del>4G的内核空间，</p><p>用户空间是进程私有的，只能自己访问和使用。堆栈、数据区、代码区都是用户空间。</p><p>内核空间是所有进程公有。绝大多数进程间通信方式，是对内核空间操作</p><h3 id="特殊的进程间通信方式："><a href="#特殊的进程间通信方式：" class="headerlink" title="特殊的进程间通信方式："></a>特殊的进程间通信方式：</h3><ul><li><p>socket通信可以实现不同主机的进程间通信。</p></li><li><p>信号通信是唯一的一种异步通信机制。</p></li><li><p>共享内存是所有IPC中效率最高的，直接对物理内存操作。</p></li></ul><h2 id="信号通信"><a href="#信号通信" class="headerlink" title="信号通信"></a>信号通信</h2><ul><li><strong>信号是软件中断，在软件层次上对中断机制的一种模拟。</strong></li><li><strong>信号是一种异步的通信机制</strong>，进程不必等待信号的到达、进程也不知道信号什么时候到达</li><li>信号可以直接进行用户空间进程和内核空间进程的交互，内核进程可以通过他来通知用户空间进程发生了哪些系统事件</li><li>每个信号的名字都以<strong>SIG</strong>开头</li><li>使用kill -l可以列出所有信号</li></ul><p><img src="/2021/03/04/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/1614858743604.png" alt="1614858743604"></p><ul><li>信号都是定义好的。不用自己定义</li></ul><h3 id="产生信号的方式"><a href="#产生信号的方式" class="headerlink" title="产生信号的方式"></a>产生信号的方式</h3><ol><li><p>用户按某些终端键时，将产生信号</p><p> 例如：“Ctrl+C”</p></li><li><p>硬件异常</p><p> 例如：无效的内存访问(除数为0)</p></li><li><p>软件异常</p></li><li><p>调用kill函数</p></li><li><p>运行kill命令</p></li></ol><h3 id="信号的默认处理方式"><a href="#信号的默认处理方式" class="headerlink" title="信号的默认处理方式"></a>信号的默认处理方式</h3><ol><li>终止进程：当信号产生后，当前进程立即结束</li><li>缺省处理：当前进程不做任何处理</li><li>停止进程：当前进程停止</li><li>让停止进程恢复运行：当信号产生后，停止的进程恢复执行(后台进程)</li></ol><p>PS：每一个信号只有一个默认的处理方式</p><h3 id="进程收到信号的处理方式"><a href="#进程收到信号的处理方式" class="headerlink" title="进程收到信号的处理方式"></a>进程收到信号的处理方式</h3><ol><li>执行系统默认动作</li><li>忽略此进程</li><li>执行自定义的信号处理函数</li></ol><p>PS：<strong>SIGKILL</strong>和<strong>SIGSTOP</strong>这两个信号只能以默认的处理方式执行，不能忽略、自定义</p><h3 id="常见信号"><a href="#常见信号" class="headerlink" title="常见信号"></a>常见信号</h3><p>TODO</p><h2 id="信号基本操作"><a href="#信号基本操作" class="headerlink" title="信号基本操作"></a>信号基本操作</h2><h4 id="kill函数"><a href="#kill函数" class="headerlink" title="kill函数"></a>kill函数</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">kill</span><span class="params">(<span class="keyword">pid_t</span> pid, <span class="keyword">int</span> signum)</span></span>;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">功能：</span></span><br><span class="line"><span class="comment">    给指定进程发送信号</span></span><br><span class="line"><span class="comment">参数：</span></span><br><span class="line"><span class="comment">    pid：四种情况</span></span><br><span class="line"><span class="comment">    signum：信号编号</span></span><br><span class="line"><span class="comment">    </span></span><br><span class="line"><span class="comment">    pid四种情况：</span></span><br><span class="line"><span class="comment">    pid&gt;0: 将信号传送给进程 ID 为 pid 的进程。 </span></span><br><span class="line"><span class="comment">    pid=0: 将信号传送给当前进程所在进程组中的所有进程。 </span></span><br><span class="line"><span class="comment">    pid=-1: 将信号传送给系统内所有的进程。 </span></span><br><span class="line"><span class="comment">    pid&lt;-1: 将信号传给指定进程组的所有进程。这个进程组号等于 pid 的绝对值。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="comment">//示例</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">pid_t</span> pid;</span><br><span class="line">    pid = fork();</span><br><span class="line">    <span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>) <span class="comment">//</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;this is father proc\n&quot;</span>);</span><br><span class="line">            sleep(<span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;this is son proc\n&quot;</span>);</span><br><span class="line">        <span class="comment">//子进程在3s后，让父进程退出</span></span><br><span class="line">        sleep(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">///使用kill给父进程发送信号</span></span><br><span class="line">        kill(getppid(), SIGINT);</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><span class="line"></span><br><span class="line"><span class="comment">//执行结果</span></span><br><span class="line"><span class="keyword">this</span> is father proc</span><br><span class="line"><span class="keyword">this</span> is son proc</span><br><span class="line"><span class="keyword">this</span> is father proc</span><br><span class="line"><span class="keyword">this</span> is father proc</span><br></pre></td></tr></table></figure><h4 id="alarm函数"><a href="#alarm函数" class="headerlink" title="alarm函数"></a>alarm函数</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="title">alarm</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> seconds)</span></span>;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">功能：</span></span><br><span class="line"><span class="comment">    定时器、闹钟，当设定的时间到达时，会产生SIGALRM信号</span></span><br><span class="line"><span class="comment">参数：</span></span><br><span class="line"><span class="comment">    seconds：设定的秒数</span></span><br><span class="line"><span class="comment">    </span></span><br><span class="line"><span class="comment">    pid四种情况：</span></span><br><span class="line"><span class="comment">    如果alarm函数之前没有alarm设置，则返回0</span></span><br><span class="line"><span class="comment">    如果有，则返回上一个alarm剩余的时间</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="comment">//示例</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//当执行完alarm后，代码会接着执行，当设定时间到后，会产生SIGALRM信号</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//如果alarm之前没有设置其他闹钟，则返回0，如果之前设置了，则返回之前剩余的秒数</span></span><br><span class="line">    <span class="comment">//如果一个程序中出现多个alarm闹钟，第一个如果没有到达指定的时间爱你就遇到第二个闹钟</span></span><br><span class="line">    <span class="comment">// 则第一个闹钟的时间清除，按照第二个alarm闹钟时间继续向下运行</span></span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">int</span> sec;</span><br><span class="line"></span><br><span class="line">    sec = alarm(<span class="number">5</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;sec = %d\n&quot;</span>, sec);</span><br><span class="line"></span><br><span class="line">    sleep(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">    sec = alarm(<span class="number">6</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;sec = %d\n&quot;</span>, sec);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;hello world\n&quot;</span>);</span><br><span class="line">        sleep(<span class="number">1</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><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//执行结果</span></span><br><span class="line">sec = <span class="number">0</span></span><br><span class="line">sec = <span class="number">2</span></span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">Alarm clock</span><br></pre></td></tr></table></figure><h4 id="raise函数"><a href="#raise函数" class="headerlink" title="raise函数"></a>raise函数</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">raise</span><span class="params">(<span class="keyword">int</span> sig)</span></span>;</span><br><span class="line"></span><br><span class="line">功能：</span><br><span class="line">    给调用进程本身发送信号</span><br><span class="line">参数：</span><br><span class="line">    sig: 指定的信号</span><br><span class="line">返回值：</span><br><span class="line">    成功 <span class="number">0</span></span><br><span class="line">    失败 非<span class="number">0</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">//案例</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;hello world\n&quot;</span>);</span><br><span class="line">        sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">        num++;</span><br><span class="line">        <span class="comment">// 当循环执行5s后，进程退出</span></span><br><span class="line">        <span class="keyword">if</span>(num == <span class="number">5</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// 使用raise给当前进程本身发送信号</span></span><br><span class="line">            raise(SIGINT);</span><br><span class="line">        &#125;</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 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">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br></pre></td></tr></table></figure><h4 id="abort函数"><a href="#abort函数" class="headerlink" title="abort函数"></a>abort函数</h4><p><strong>即使SIGABRT信号加入阻塞集，一旦进程调用了abort函数，进程还是会被终止，且在终止前会刷新缓冲区，关闭文件描述符</strong></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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">abort</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">功能：向进程发送一个SIGABRT信号，默认情况下进程会退出</span><br><span class="line">参数：无</span><br><span class="line">返回值：无</span><br><span class="line">    </span><br><span class="line"><span class="comment">//案例</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;hello world\n&quot;</span>);</span><br><span class="line">        sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">        num++;</span><br><span class="line">        <span class="comment">// 当循环执行5s后，进程退出</span></span><br><span class="line">        <span class="keyword">if</span> (num == <span class="number">5</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// 使用raise给当前进程本身发送信号</span></span><br><span class="line">            <span class="built_in">abort</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="keyword">return</span> <span class="number">0</span>; <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">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">hello world</span><br><span class="line">Aborted   </span><br></pre></td></tr></table></figure><h4 id="pause函数"><a href="#pause函数" class="headerlink" title="pause函数"></a>pause函数</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">pause</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line">功能：</span><br><span class="line">将调用进程挂起直至捕捉到信号为止。这个函数通常用于判断信号是否已到。</span><br><span class="line">返回值：</span><br><span class="line">直到捕捉到信号，pause信号才返回<span class="number">-1</span>，且errno被设置成EINTR</span><br><span class="line"></span><br><span class="line"><span class="comment">//案例</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">pid_t</span> pid;</span><br><span class="line">    pid = fork();</span><br><span class="line">    <span class="keyword">if</span> (pid &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fork&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (pid &gt; <span class="number">0</span>) <span class="comment">//</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;this is father proc\n&quot;</span>);</span><br><span class="line">        <span class="comment">// 使用pause函数阻塞等待捕捉信号</span></span><br><span class="line">        pause();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;this is son proc\n&quot;</span>);</span><br><span class="line">        <span class="comment">//子进程在3s后，让父进程退出</span></span><br><span class="line">        sleep(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">///使用kill给父进程发送信号</span></span><br><span class="line">        kill(getppid(), SIGINT);</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><span class="line"></span><br><span class="line"><span class="comment">//执行结果</span></span><br><span class="line"><span class="keyword">this</span> is father proc</span><br><span class="line"><span class="keyword">this</span> is son proc</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="signal函数"><a href="#signal函数" class="headerlink" title="signal函数"></a>signal函数</h4><p><strong>程序中可用signal()改变信号的处理方式</strong></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><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="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">void</span> <span class="params">(*<span class="keyword">sighandler_t</span>)</span><span class="params">(<span class="keyword">int</span>)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">sighandler_t</span> <span class="title">signal</span><span class="params">(<span class="keyword">int</span> signum,<span class="keyword">sighandler_t</span> handler)</span></span>;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">功能：注册信号处理函数（不可用于 SIGKILL、SIGSTOP 信号），即确定收到信号后处理函数的入口地址。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">参数： </span></span><br><span class="line"><span class="comment">signum：信号编号</span></span><br><span class="line"><span class="comment">handler：处理方式 </span></span><br><span class="line"><span class="comment">SIG_IGN 当信号产生时，以缺省（忽略）的方式处理</span></span><br><span class="line"><span class="comment">SIG_DFL 当信号产生时，以当前信号默认的方式处理  </span></span><br><span class="line"><span class="comment">自定义信号处理函数：信号处理函数名</span></span><br><span class="line"><span class="comment">返回值：</span></span><br><span class="line"><span class="comment">成功：返回函数指针，该地址为此信号上一次注册的信号处理函数的地址</span></span><br><span class="line"><span class="comment">失败：SIG_ERR</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h5 id="signal函数的使用"><a href="#signal函数的使用" class="headerlink" title="signal函数的使用"></a>signal函数的使用</h5><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><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">handler</span><span class="params">(<span class="keyword">int</span> sig)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//以默认的方式处理信号</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line">    <span class="keyword">if</span> (signal(SIGINT, SIG_DFL) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (signal(SIGQUIT, SIG_DFL) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (signal(SIGTSTP, SIG_DFL) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//以忽略的方式处理信号</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line">    <span class="keyword">if</span> (signal(SIGINT, SIG_IGN) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (signal(SIGQUIT, SIG_IGN) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (signal(SIGTSTP, SIG_IGN) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//kill\stop信号只能以默认的方式处理，不能忽略或者捕捉</span></span><br><span class="line">    <span class="comment">// if (signal(SIGKILL, SIG_IGN) == SIG_ERR)</span></span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     perror(&quot;fail to signal&quot;);</span></span><br><span class="line">    <span class="comment">//     exit(1);</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//以用户自定义的方式处理信号</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 1</span></span><br><span class="line">    <span class="keyword">if</span> (signal(SIGINT, handler) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (signal(SIGQUIT, handler) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (signal(SIGTSTP, handler) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;hello world\n&quot;</span>);</span><br><span class="line">        sleep(<span class="number">1</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><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">handler</span><span class="params">(<span class="keyword">int</span> sig)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (sig == SIGINT)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;SIGINT正在处理\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (sig == SIGQUIT)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;SIGQUIT正在处理\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (sig == SIGTSTP)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;SIGTSTP正在处理\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="signal函数的返回值"><a href="#signal函数的返回值" class="headerlink" title="signal函数的返回值"></a>signal函数的返回值</h5><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">handler</span><span class="params">(<span class="keyword">int</span> sig)</span></span>;</span><br><span class="line"><span class="keyword">void</span> *ret_handler;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>((ret_handler = signal(SIGINT,handler)) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal\n&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;hello world\n&quot;</span>);</span><br><span class="line">        sleep(<span class="number">1</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><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">handler</span><span class="params">(<span class="keyword">int</span> sig)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;*****************\n&quot;</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;test\n&quot;</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;*****************\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (signal(SIGINT, ret_handler) == SIG_ERR)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;fail to signal\n&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</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><strong>可重入函数是指函数可以由多个任务并发使用，而不必担心数据错误</strong></p><p>可重入函数就是可以被中断的函数，当前函数可以在任何时刻中断它，并执行另一块代码。当执行完毕后，回到原本的代码还可以继续正常运行</p><p>编写可重入函数：</p><ul><li>不使用(返回)静态的数据、全局变量(除非用信号量互斥)</li><li>不调用动态内存分配、释放函数</li><li>不调用任何不可重入的函数(如标准I/O函数)</li></ul><p><strong>即使信号处理函数使用的都是可重入函数(常见的可重入函数)，也要注意进入处理函数时，首先要保存errno的值，结束时，在恢复原值。因为在信号处理过程中，errno值随时可能被改变</strong></p><h2 id="信号集"><a href="#信号集" class="headerlink" title="信号集"></a>信号集</h2><h3 id="信号集概述"><a href="#信号集概述" class="headerlink" title="信号集概述"></a>信号集概述</h3><p>一个用户进程常常需要对多个信号做出处理。为了方便对多个信号进行处理，在Linux系统中引入了信号集。信号集是用来表示多个信号的数据结构。</p><h3 id="信号集数据类型"><a href="#信号集数据类型" class="headerlink" title="信号集数据类型"></a>信号集数据类型</h3><p>sigset_t</p><h1 id="管道、命名管道"><a href="#管道、命名管道" class="headerlink" title="管道、命名管道"></a>管道、命名管道</h1><h3 id="无名管道概述"><a href="#无名管道概述" class="headerlink" title="无名管道概述"></a>无名管道概述</h3><p>管道又叫无名管道</p><p>无名管道是一种特殊类型的文件，在应用层体现为两个打开的文件描述符</p><p>任何个进程创建的时候，系统都会给他分配4G的虚拟内存，分为3G用户空间和1G内核空间，内核空间是所有进程公有的，<strong>无名管道就是创建在内核空间的</strong>，多个进程知道同一个无名管道的空间，就可以利用他进行通信</p><p><img src="/2021/03/04/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/image-20210314212606622.png" alt="image-20210314212606622"></p><p>无名管道虽然是在内核空间创建的，但是会给当前用户进程两个文件描述符，一个负责读操作，一个负责执行写操作。</p><p>管道特点：</p><ol><li>半双工，数据在同一时刻只能在一个方向上流动。</li><li>数据只能从管道的一端写入，另一端读出。</li><li>写入管道中的数据符合先进先出的规则。</li><li>管道传送的数据是无格式的，这要求管道的双方约定好数据格式</li><li>管道不是普通文件，不属于某一个文件系统，只存在内存中</li></ol>]]></content>
    
    
    <summary type="html">系统编程</summary>
    
    
    
    <category term="视频笔记" scheme="https://ethereal14.github.io/categories/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Linux 系统编程" scheme="https://ethereal14.github.io/tags/Linux-%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>Linux C 网络编程</title>
    <link href="https://ethereal14.github.io/2021/03/04/Linux-C-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"/>
    <id>https://ethereal14.github.io/2021/03/04/Linux-C-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/</id>
    <published>2021-03-04T08:24:51.000Z</published>
    <updated>2023-03-12T16:03:10.137Z</updated>
    
    <content type="html"><![CDATA[<h2 id="第一章"><a href="#第一章" class="headerlink" title="第一章"></a>第一章</h2><h2 id="第二章"><a href="#第二章" class="headerlink" title="第二章"></a>第二章</h2><h2 id="第三章"><a href="#第三章" class="headerlink" title="第三章"></a>第三章</h2><h3 id><a href="#" class="headerlink" title></a></h3><h3 id="-1"><a href="#-1" class="headerlink" title></a></h3><h3 id="网络字节序与地址转换"><a href="#网络字节序与地址转换" class="headerlink" title="网络字节序与地址转换"></a>网络字节序与地址转换</h3><table><thead><tr><th>保存数据方式</th><th>解析数据方式</th></tr></thead><tbody><tr><td>大端序</td><td>高位字节放在低位地址</td></tr><tr><td>小端序</td><td>低位字节放在高位地址</td></tr></tbody></table><h4 id="字节序转换相关函数"><a href="#字节序转换相关函数" class="headerlink" title="字节序转换相关函数"></a>字节序转换相关函数</h4><p>​        short–&gt;占用2字节、long–&gt;占用4字节(Linux)</p><table><thead><tr><th>函数名</th><th>作用等</th></tr></thead><tbody><tr><td>htonl()</td><td>用于IP地址转换</td></tr><tr><td>htons()</td><td>用于端口号转换</td></tr></tbody></table><h5 id="字节序转换函数实例"><a href="#字节序转换函数实例" class="headerlink" title="字节序转换函数实例"></a>字节序转换函数实例</h5><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">short</span> host_port = <span class="number">0x1234</span>;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">short</span> net_port;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> host_addr = <span class="number">0x12345678</span>;</span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> net_addr;</span><br><span class="line"></span><br><span class="line">    net_addr = htonl(host_addr);</span><br><span class="line">    net_port = htons(host_port);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Host order port: %#x\n&quot;</span>, host_port);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Net order port: %#x\n&quot;</span>, net_port);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Host order address: %#lx\n&quot;</span>, host_addr);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Net order address: %#lx\n&quot;</span>, net_addr);</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><span class="line"></span><br><span class="line"><span class="comment">/************* 执行结果 ************/</span></span><br><span class="line">Host order port: <span class="number">0x1234</span></span><br><span class="line">Net order port: <span class="number">0x3412</span></span><br><span class="line">Host order address: <span class="number">0x12345678</span></span><br><span class="line">Net order address: <span class="number">0x78563412</span></span><br></pre></td></tr></table></figure><p><strong>数据在传输过程中不需要考虑字节序问题(除了向sockaddr_in填充数据外)</strong></p><h3 id="网络地址的初始化与分配"><a href="#网络地址的初始化与分配" class="headerlink" title="网络地址的初始化与分配"></a>网络地址的初始化与分配</h3><h4 id="将字符串信息转换为网络字节序的整数型"><a href="#将字符串信息转换为网络字节序的整数型" class="headerlink" title="将字符串信息转换为网络字节序的整数型"></a>将字符串信息转换为网络字节序的整数型</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/************* 头文件等 *************/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">in_addr_t</span><span class="title">inet_addr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *<span class="built_in">string</span>)</span></span>;</span><br><span class="line">成功返回<span class="number">32</span>位大端序整数型值，失败返回INADDR_NONE</span><br><span class="line">  </span><br><span class="line"><span class="comment">/************* 代码示例 ************/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">char</span> *addr1 = <span class="string">&quot;1.2.3.4&quot;</span>;</span><br><span class="line">    <span class="keyword">char</span> *addr2 = <span class="string">&quot;1.2.3.256&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> conv_addr = inet_addr(addr1);</span><br><span class="line">    <span class="keyword">if</span> (conv_addr == INADDR_NONE)</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error occurred! \n&quot;</span>);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Network ordered integer addr: %#lx \n&quot;</span>, conv_addr);</span><br><span class="line"></span><br><span class="line">    conv_addr = inet_addr(addr2);</span><br><span class="line">    <span class="keyword">if</span> (conv_addr == INADDR_NONE)</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error occurred! \n&quot;</span>);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Network ordered integer addr: %#lx \n&quot;</span>, conv_addr);</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><span class="line"></span><br><span class="line"><span class="comment">/************* 执行结果 ************/</span></span><br><span class="line">Network ordered integer addr: <span class="number">0x4030201</span> </span><br><span class="line">Error occurred! </span><br><span class="line"></span><br><span class="line">一个字节能表示的最大整数位<span class="number">255</span>，所以第二个错的</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/************* 头文件等 *************/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">inet_aton</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> * <span class="built_in">string</span>, struct in_addr *addr)</span></span>;</span><br><span class="line">成功返回<span class="number">1</span>，失败返回<span class="number">0</span></span><br><span class="line">    </span><br><span class="line"><span class="built_in">string</span>: 含有需要转换的IP地址信息的字符串地址值</span><br><span class="line">addr:将保存转换结果的in_addr结构体变量的地址值</span><br><span class="line"><span class="comment">/************* 代码示例 ************/</span></span><br><span class="line"> <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">error_handler</span><span class="params">(<span class="keyword">char</span> *message)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">char</span> *addr = <span class="string">&quot;127.232.124.79&quot;</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">addr_inet</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!inet_aton(addr, &amp;addr_inet.sin_addr))</span><br><span class="line">    &#123;</span><br><span class="line">        error_handler(<span class="string">&quot;Conversion error&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;NetWork order integer addr: %#x \n&quot;</span>, addr_inet.sin_addr.s_addr);</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><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">error_handler</span><span class="params">(<span class="keyword">char</span> *message)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">fputs</span>(message, <span class="built_in">stderr</span>);</span><br><span class="line">    fputc(<span class="string">&#x27;\n&#x27;</span>, <span class="built_in">stderr</span>);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</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">NetWork order integer addr: <span class="number">0x4f7ce87f</span> </span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>inet_addr函数和inet_aton函数功能完全相同。但是inet_aton函数会自动把结果存入sockaddr_in结构体中</strong></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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/************* 头文件等 *************/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">char</span> *<span class="title">inet_aton</span><span class="params">(struct in_addr addr)</span></span>;</span><br><span class="line">成功返回转换字符串地址值，失败返回<span class="number">-1</span></span><br><span class="line">    </span><br><span class="line"><span class="comment">/************* 代码示例 ************/</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">addr1</span>, <span class="title">addr2</span>;</span></span><br><span class="line">    <span class="keyword">char</span> *str_ptr;</span><br><span class="line">    <span class="keyword">char</span> str_arr[<span class="number">20</span>];</span><br><span class="line"></span><br><span class="line">    addr1.sin_addr.s_addr = htonl(<span class="number">0x1020304</span>);</span><br><span class="line">    addr2.sin_addr.s_addr = htonl(<span class="number">0x1010101</span>);</span><br><span class="line"></span><br><span class="line">    str_ptr = inet_ntoa(addr1.sin_addr);</span><br><span class="line">    <span class="built_in">strcpy</span>(str_arr, str_ptr);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;notation1 :%s \n&quot;</span>, str_ptr);</span><br><span class="line"></span><br><span class="line">    inet_ntoa(addr2.sin_addr);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;notation2 :%s \n&quot;</span>, str_ptr);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;notation3 :%s \n&quot;</span>, str_arr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>; <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">notation1 :<span class="number">1.2</span><span class="number">.3</span><span class="number">.4</span> </span><br><span class="line">notation2 :<span class="number">1.1</span><span class="number">.1</span><span class="number">.1</span> </span><br><span class="line">notation3 :<span class="number">1.2</span><span class="number">.3</span><span class="number">.4</span> </span><br></pre></td></tr></table></figure><h2 id="第四章"><a href="#第四章" class="headerlink" title="第四章"></a>第四章</h2><h3 id="理解TCP和UDP"><a href="#理解TCP和UDP" class="headerlink" title="理解TCP和UDP"></a>理解TCP和UDP</h3><p>根据传输方式的不同，基于网络协议的套接字一般分为TCP套接字和UDO套接字。因为TCP套接字是面向连接，因此又称为基于流(stream)的套接字。</p><h4 id="TCP-IP协议栈"><a href="#TCP-IP协议栈" class="headerlink" title="TCP/IP协议栈"></a>TCP/IP协议栈</h4><p><img src="/2021/03/04/Linux-C-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/image-20210313103849273.png" alt="image-20210313103849273"></p><p>TCP/IP协议栈分4层：链路层、IP层、传输层、应用层</p><p>OSI模型分7层：物理层、数据链路层、网络层、传输层、会话层、表示层、应用层</p><h3 id="基于TCP的服务端-客户端"><a href="#基于TCP的服务端-客户端" class="headerlink" title="基于TCP的服务端/客户端"></a>基于TCP的服务端/客户端</h3><h4 id="TCP服务端默认函数调用顺序："><a href="#TCP服务端默认函数调用顺序：" class="headerlink" title="TCP服务端默认函数调用顺序："></a>TCP服务端默认函数调用顺序：</h4><ol><li>socket()            创建套接字</li><li>bind()                分配套接字地址</li><li>listen()              等待连接请求状态</li><li>accept()            允许连接</li><li>read()/write()   数据交换</li><li>close()             断开连接</li></ol><h4 id="TCP客户端默认函数调用顺序"><a href="#TCP客户端默认函数调用顺序" class="headerlink" title="TCP客户端默认函数调用顺序"></a>TCP客户端默认函数调用顺序</h4><ol><li>socket()</li><li>connect()</li><li>read()/write()</li><li>close()</li></ol><h4 id="函数调用关系"><a href="#函数调用关系" class="headerlink" title="函数调用关系"></a>函数调用关系</h4><p>服务器创建套接字后连续调用bind、listen函数进入等待状态，客户端通过调用connect函数发起连接请求。</p><p>注意：客户端只有等到服务端调用listen函数以后才能调用connect函数。同时，客户端调用connect函数前，服务端可能率先调用accept函数，当然，磁石服务端在调用accept函数时进入阻塞(blocking)状态，知道客户端调用connect函数为止。</p><p><img src="/2021/03/04/Linux-C-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/image-20210313180346859.png" alt="image-20210313180346859"></p><h3 id="实现迭代服务器端-客户端"><a href="#实现迭代服务器端-客户端" class="headerlink" title="实现迭代服务器端/客户端"></a>实现迭代服务器端/客户端</h3><p>实现服务端将客户端传输的字符串数据原封不动的传回客户端。</p><p>目前该服务端同一时刻只能服务一个客户端。</p><h4 id="迭代回声服务器端-客户端"><a href="#迭代回声服务器端-客户端" class="headerlink" title="迭代回声服务器端/客户端"></a>迭代回声服务器端/客户端</h4><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><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//echo_server.c</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUF_SIZE 1024</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">error_handler</span><span class="params">(<span class="keyword">char</span> *message)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> server_sock, client_sock;</span><br><span class="line">    <span class="keyword">char</span> message[BUF_SIZE];</span><br><span class="line">    <span class="keyword">int</span> str_len, i;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">server_addr</span>, <span class="title">client_addr</span>;</span></span><br><span class="line">    <span class="keyword">socklen_t</span> client_addr_size;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (argc != <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s &lt;port&gt;\n&quot;</span>, argv[<span class="number">0</span>]);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    server_sock = socket(PF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    <span class="keyword">if</span> (server_sock == <span class="number">-1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        error_handler(<span class="string">&quot;socket() error&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">memset</span>(&amp;server_addr, <span class="number">0</span>, <span class="keyword">sizeof</span>(server_addr));</span><br><span class="line">    server_addr.sin_family = AF_INET;</span><br><span class="line">    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);</span><br><span class="line">    server_addr.sin_port = htons(atoi(argv[<span class="number">1</span>]));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (bind(server_sock, (struct sockaddr *)&amp;server_addr,</span><br><span class="line">             <span class="keyword">sizeof</span>(server_addr)) == <span class="number">-1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        error_handler(<span class="string">&quot;bind() error&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (listen(server_sock, <span class="number">5</span>) == <span class="number">-1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        error_handler(<span class="string">&quot;listen() error&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    client_addr_size = <span class="keyword">sizeof</span>(client_addr_size);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        client_sock = accept(server_sock,</span><br><span class="line">                             (struct sockaddr *)&amp;client_addr,</span><br><span class="line">                             &amp;client_addr_size);</span><br><span class="line">        <span class="keyword">if</span> (client_sock == <span class="number">-1</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            error_handler(<span class="string">&quot;accept() error&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;Conected client %d\n&quot;</span>, i + <span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span> ((str_len = read(client_sock,</span><br><span class="line">                               message, BUF_SIZE)) != <span class="number">0</span>)</span><br><span class="line">            write(client_sock, message, str_len);</span><br><span class="line">        close(client_sock);</span><br><span class="line">    &#125;</span><br><span class="line">    close(server_sock);</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><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">error_handler</span><span class="params">(<span class="keyword">char</span> *message)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">fputs</span>(message, <span class="built_in">stderr</span>);</span><br><span class="line">    fputc(<span class="string">&#x27;\n&#x27;</span>, <span class="built_in">stderr</span>);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//echo_client.c</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> BUF_SIZE 1024</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">error_handler</span><span class="params">(<span class="keyword">char</span> *message)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> sock;</span><br><span class="line">    <span class="keyword">char</span> message[BUF_SIZE];</span><br><span class="line">    <span class="keyword">int</span> str_len = <span class="number">0</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">server_addr</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (argc != <span class="number">3</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s &lt;IP&gt; &lt;PORT&gt;\n&quot;</span>, argv[<span class="number">0</span>]);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    sock = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">    <span class="keyword">if</span> (sock == <span class="number">-1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        error_handler(<span class="string">&quot;socket() error&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">memset</span>(&amp;server_addr, <span class="number">0</span>, <span class="keyword">sizeof</span>(server_addr));</span><br><span class="line">    server_addr.sin_family = AF_INET;</span><br><span class="line">    server_addr.sin_addr.s_addr = inet_addr(argv[<span class="number">1</span>]);</span><br><span class="line">    server_addr.sin_port = htons(atoi(argv[<span class="number">2</span>]));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (connect(sock, (struct sockaddr *)&amp;server_addr,</span><br><span class="line">                <span class="keyword">sizeof</span>(server_addr)) == <span class="number">-1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        error_handler(<span class="string">&quot;connect() error&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Connect..............\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">fputs</span>(<span class="string">&quot;Input message(Q to quit):&quot;</span>, <span class="built_in">stdout</span>);</span><br><span class="line">        fgets(message, BUF_SIZE, <span class="built_in">stdin</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(message, <span class="string">&quot;q\n&quot;</span>) || !<span class="built_in">strcmp</span>(message, <span class="string">&quot;Q\n&quot;</span>))</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        write(sock, message, <span class="built_in">strlen</span>(message));</span><br><span class="line">        str_len = read(sock, message, BUF_SIZE - <span class="number">1</span>);</span><br><span class="line">        message[str_len] = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Message from server: %s\n&quot;</span>, message);</span><br><span class="line">    &#125;</span><br><span class="line">    close(sock);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">error_handler</span><span class="params">(<span class="keyword">char</span> *message)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">fputs</span>(message, <span class="built_in">stderr</span>);</span><br><span class="line">    fputc(<span class="string">&#x27;\n&#x27;</span>, <span class="built_in">stderr</span>);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="第五章"><a href="#第五章" class="headerlink" title="第五章"></a>第五章</h2><h2 id="第六章"><a href="#第六章" class="headerlink" title="第六章"></a>第六章</h2><h2 id="第七章"><a href="#第七章" class="headerlink" title="第七章"></a>第七章</h2><h2 id="第八章"><a href="#第八章" class="headerlink" title="第八章"></a>第八章</h2>]]></content>
    
    
    <summary type="html">学习尹圣雨的《TCP/IP网络编程》</summary>
    
    
    
    <category term="读书笔记" scheme="https://ethereal14.github.io/categories/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Linux 网络编程" scheme="https://ethereal14.github.io/tags/Linux-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>嵌入式笔试题笔记</title>
    <link href="https://ethereal14.github.io/2021/01/28/%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%AC%94%E8%AF%95%E9%A2%98%E7%AC%94%E8%AE%B0/"/>
    <id>https://ethereal14.github.io/2021/01/28/%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%AC%94%E8%AF%95%E9%A2%98%E7%AC%94%E8%AE%B0/</id>
    <published>2021-01-28T07:29:41.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    <content type="html"><![CDATA[<h2 id="寒武纪笔试题"><a href="#寒武纪笔试题" class="headerlink" title="寒武纪笔试题"></a>寒武纪笔试题</h2><ol><li><p><strong>单片机IO口开漏输出和推挽输出有什么区别？</strong> </p><p> 开漏输出：只能输出低电平，如果要输出高电平必须通过上拉电阻才能实现。就类似于三极管的集电极输出。</p></li></ol><pre><code>推挽输出：推挽输出既可以输出低电平，也可以输出高电平，可以直接驱动功耗不大的数字器件。导通损耗小、效率高、既提高电路的负载能力，又提高开关速度</code></pre><p><strong>补充</strong>：</p><ul><li>上拉&amp;下拉输出电阻作用： 防止输入端悬空，减少外部电流对芯片的干扰，限流，增加高电平输出时的驱动能力。</li><li>浮空输入：IO的电平是不确定的，有外部输入决定。多用于外部按键。</li><li>模拟输入： 即关闭施密特触发器，将电压信号传送到片上外设模块(不接上下拉电阻)。 </li></ul><ol start="2"><li><p><strong>单片机里定时器有什么作用和优势？</strong> </p><p> 作用：计数器、延时、输入捕获（解码和测量时间间隔）、输出比较（主要输出PWM波）、单脉冲输出、触发中断（对其他模块进行操作）</p><p> 优势：不需要CPU参与，精确</p></li></ol><ol start="3"><li><p><strong>什么是Nyquist采样定理？如果需要通过512点FFT分析200-10KHz信号频谱，频谱分辨率不低于40Hz，此时采样频率需在什么范围？</strong> </p><p> ​            频率分辨率可以理解为在使用DFT时，在频率轴上的所能得到的最小频率间隔f0=fs/N=1/NTs=1/T,其中N为            采样点数，fs为采样频率，Ts为采样间隔。所以采样频率不低于20480hz.与采样频率的不低于20000hz综            合得不低于20480hz <strong>（做不来、也没看懂解析）</strong></p></li></ol><ol start="4"><li><p><strong>已知单片机内置12位精度的ADC，单片机工作电压3.3V，ADC基准电压3V，请计算ADC采样的电压最小分辨率是多少？如果单片机ADC输入口电压为1V，则采样得到的值是多少？</strong></p><p> ​        3.3/4096 V         4096/3.3(自己的答案)</p><p> ​        3/4096 v            1365(4096/3)(评论区答案)</p></li></ol><ol start="5"><li><p><strong>同步通信和异步通信有什么区别？UART、SPI和I2C分别属于什么类型的通信方式？</strong> </p><p> ​    同步通信： 发送端与接收端时钟频率一致。 逐字符发送，无间隙。通信效率高。</p><p> ​    异步通信： 不要求接收端时钟和发送端时钟同步。 需要有起始位和停止位，传输效率较低。</p><p> ​    UART：异步通信。</p><p> ​    SPI：同步通信。</p><p> ​    I2C：同步通信</p></li></ol><ol start="6"><li><p><strong>简述通过I2C接口读取设备X的寄存器Y的值的过程</strong> </p><p> 发送i2c开始信号-发送设备x的地址-等待设备应答-发送寄存器Y的地址-等待应答-发送i2c开始信号-发送设备X的读地址-等待设备应答-接收寄存器Y的数据-等待应答-停止i2c</p></li></ol><ol start="7"><li><p><strong>中断是什么？请简述单片机中断处理的过程</strong> </p><p> 中断： CPU在正常执行程序的过程中，由于内部/外部事件的触发或程序的预先安排引起CPU暂时中断当前正在运行的程序，而转去执行中断服务子程序，待中断服务子程序执行完毕后，CPU继续执行原来的程序</p><p>   <strong>中断处理的过程：</strong></p><p> ​    第一步：保护现场，将当前位置的PC地址压栈；</p><p> ​    第二步：跳转到中断服务程序，执行中断服务程序；</p><p> ​    第三步：恢复现场，将栈顶的值回送给PC；<br> ​    第四步：跳转到被中断的位置开始执行下一个指令； </p></li></ol><ol start="8"><li><p><strong>相比于正常子函数，中断服务函数有什么特点和需要注意的地方？</strong> </p><p> ​    无返回值、不能向中断服务函数传递参数、短小、需要快进快出、不能递归调用自身 </p></li></ol><ol start="9"><li><p><strong>对于char型变量 a，写两段代码分别将 a的 bit 6置1和置0</strong> </p><p> ​    a| = (a&lt;&lt;6);</p><p> ​    a&amp; = ~(a&lt;&lt;6);</p></li></ol><ol start="10"><li><p><strong>请写一段代码，可以将输入为”0.0.0.0”—“255.255.255.255”的字符串转换为int型整数数组。</strong></p><p><strong>输入：”255.255.255.255”</strong></p><p><strong>输出：255 255 255 255 （数组）</strong></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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="keyword">char</span> ch[<span class="number">20</span>];</span><br><span class="line"><span class="keyword">int</span> num[<span class="number">20</span>],len = <span class="number">0</span>,count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%s&quot;</span>, ch);</span><br><span class="line">len = <span class="built_in">strlen</span>(ch);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d\n&quot;</span>, len);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; len; i++)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (ch[i] == <span class="string">&#x27;.&#x27;</span>)</span><br><span class="line">&#123;</span><br><span class="line">count++;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line">&#125;</span><br><span class="line">num[count] *= <span class="number">10</span>;</span><br><span class="line">num[count] += (ch[i] - <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d &quot;</span>, num[i]);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol>]]></content>
    
    
    <summary type="html">笔试题笔记</summary>
    
    
    
    <category term="笔面试相关" scheme="https://ethereal14.github.io/categories/%E7%AC%94%E9%9D%A2%E8%AF%95%E7%9B%B8%E5%85%B3/"/>
    
    
    <category term="笔试" scheme="https://ethereal14.github.io/tags/%E7%AC%94%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>linux驱动框架总结</title>
    <link href="https://ethereal14.github.io/2020/12/14/linux%E9%A9%B1%E5%8A%A8%E6%A1%86%E6%9E%B6%E6%80%BB%E7%BB%93/"/>
    <id>https://ethereal14.github.io/2020/12/14/linux%E9%A9%B1%E5%8A%A8%E6%A1%86%E6%9E%B6%E6%80%BB%E7%BB%93/</id>
    <published>2020-12-14T13:06:55.000Z</published>
    <updated>2023-03-12T16:03:10.201Z</updated>
    
    <content type="html"><![CDATA[<h4 id="常用头文件"><a href="#常用头文件" class="headerlink" title="常用头文件"></a>常用头文件</h4><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><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/init.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/module.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/fs.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/cdev.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/platform_device.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/device.h&gt;</span></span></span><br><span class="line">......</span><br></pre></td></tr></table></figure><h4 id="字符型驱动基本框架"><a href="#字符型驱动基本框架" class="headerlink" title="字符型驱动基本框架"></a>字符型驱动基本框架</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//常用宏定义、全局变量</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DEV_NAME <span class="meta-string">&quot;xxx&quot;</span> <span class="comment">//定义设备名称，Linux下可用ls /dev/查看</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DEV_CNT (x) <span class="comment">//设备数量</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">dev_t</span> devno; <span class="comment">//字符设备的设备号</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="keyword">class</span> *<span class="title">dev_class</span>;</span> <span class="comment">//保存创建的类</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 保存创建的设备</span></span><br><span class="line"><span class="comment">//struct device *device_dev;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//设备树节点结构体</span></span><br><span class="line"><span class="comment">//struct device_node *dev_node; </span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">dev_open</span><span class="params">(struct inode *inode,struct file *filp)</span> <span class="comment">//.open函数实现</span></span></span><br><span class="line"><span class="function"></span>&#123;</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><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">dev_write</span><span class="params">(struct file *filp, <span class="keyword">const</span> <span class="keyword">char</span> __user *buf, <span class="keyword">size_t</span> cnt, <span class="keyword">loff_t</span> *off)</span><span class="comment">//.write函数实现</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</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><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">ssize_t</span> <span class="title">dev_read</span><span class="params">(struct file *filp,<span class="keyword">char</span> __user *buf,<span class="keyword">size_t</span> cnt, <span class="keyword">loff_t</span> *off)</span><span class="comment">//.read函数实现</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</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><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">dev_release</span><span class="params">(struct inode *inode, struct file *filp)</span><span class="comment">//.release函数实现</span></span></span><br><span class="line"><span class="function"></span>&#123;</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><span class="line"><span class="comment">//文件操作结构体</span></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">chr_dev_fops</span> =</span> &#123;</span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">    .open = dev_open,</span><br><span class="line">    .write = dev_write,</span><br><span class="line">.read = dev_read,</span><br><span class="line">    .release = dev_release,</span><br><span class="line">    ...</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="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">driver_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</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><span class="line"></span><br><span class="line"><span class="comment">//驱动出口函数</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">driver_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">......        </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">module_init(driver_init);</span><br><span class="line">module_exit(driver_exit);</span><br><span class="line"></span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;xxx&quot;</span>);</span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br></pre></td></tr></table></figure><h5 id="常用结构体、函数"><a href="#常用结构体、函数" class="headerlink" title="常用结构体、函数"></a>常用结构体、函数</h5><h4 id="平台驱动模型"><a href="#平台驱动模型" class="headerlink" title="平台驱动模型"></a>平台驱动模型</h4><p>……</p>]]></content>
    
    
    <summary type="html">写驱动学到的一点框架、待完善</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="Linux" scheme="https://ethereal14.github.io/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>wsl2编译Linux Kernel</title>
    <link href="https://ethereal14.github.io/2020/12/11/wsl2%E7%BC%96%E8%AF%91Linux-Kernel/"/>
    <id>https://ethereal14.github.io/2020/12/11/wsl2%E7%BC%96%E8%AF%91Linux-Kernel/</id>
    <published>2020-12-11T10:43:04.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    <content type="html"><![CDATA[<p>编译时会报错:</p><p><code>make[2]: *** No rule to make target &#39;/lib/firmware/imx/sdma/sdma-imx6q.bin&#39;, needed by &#39;firmware/imx/sdma/sdma-imx6q.bin.gen.o&#39;. Stop.</code></p><p>缺少一个sdma的固件</p><p>经过一番百度。把wsl2 Ubuntu打开了32位库支持，编译还是报错。</p><p>最后在野火论坛找到了这个固件。放到了wsl2 Ubuntu文件根目录下的</p><p><code>lib/firmware/imx</code>里边。</p><p>其实wsl2 Ubuntu里边没有firmware这个文件夹，我自己新建了<code>firmware/imx</code>文件夹，没想到编译成功了</p>]]></content>
    
    
    <summary type="html">wsl2 Ubuntu编译野火提供的Linux内核源码遇到的一些问题</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="Linux" scheme="https://ethereal14.github.io/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>art-pi上手体验</title>
    <link href="https://ethereal14.github.io/2020/12/08/art-pi/"/>
    <id>https://ethereal14.github.io/2020/12/08/art-pi/</id>
    <published>2020-12-08T16:12:37.000Z</published>
    <updated>2023-03-12T16:03:10.149Z</updated>
    
    <content type="html"><![CDATA[<h3 id="一、先来张照片"><a href="#一、先来张照片" class="headerlink" title="一、先来张照片"></a>一、先来张照片</h3><p><img src="/2020/12/08/art-pi/IMG_20201208_210434.jpg" alt="IMG_20201208_210434"><br><img src="/2020/12/08/art-pi/IMG_20201208_210452.jpg" alt="IMG_20201208_210452"></p><p>art-pi的做工我看着是真的舒服。很符合RT-Thread官网的那句话”小而美”了。</p><h3 id="二、出厂程序体验"><a href="#二、出厂程序体验" class="headerlink" title="二、出厂程序体验"></a>二、出厂程序体验</h3><p>出厂例程是通过蓝牙对开发板进行配网，内置一个web服务器，配网成功后能够通过网页显示开发板的基本信息，并对开发板的板载LED进行简单的控制。</p><h4 id="蓝牙配网流程直接看GitHub的文档即可"><a href="#蓝牙配网流程直接看GitHub的文档即可" class="headerlink" title="蓝牙配网流程直接看GitHub的文档即可"></a>蓝牙配网流程直接看GitHub的文档即可</h4><p><img src="/2020/12/08/art-pi/Screenshot_20201208_211732_com.huawei.browser.jpg" alt="Screenshot_20201208_211732_com.huawei.browser"></p><p>配网成功以后，这个网页是真的骚，可以查看内存、norflash、SD等信息。</p><h3 id="三、驱动I2C的OLED屏幕"><a href="#三、驱动I2C的OLED屏幕" class="headerlink" title="三、驱动I2C的OLED屏幕"></a>三、驱动I2C的OLED屏幕</h3><p>其实拿到art-pi之后，并没有什么好的创意来发挥H7的实力。RT-Thread最近半年多也一直在学习，也有几个比赛我也上了rtt，但是学艺不精，比赛只取得了一个勉强看得过去的成绩。</p><p>没有新的整活，于是就只好旧活新整，把原来F103上的东西搬到ART-Pi上。</p><h5 id="物料："><a href="#物料：" class="headerlink" title="物料："></a>物料：</h5><p>OLED * 1</p><p>ART-Pi * 1</p><h5 id="平台："><a href="#平台：" class="headerlink" title="平台："></a>平台：</h5><p>RT-Thread Studio</p><h5 id="主要代码"><a href="#主要代码" class="headerlink" title="主要代码"></a>主要代码</h5><p>本来是打算用原来的方式开发的，即：用RT-Thread Nano。但是体验过了rtt软件的方便，就不想自己手写外设驱动了，抱着试一下的心态，搜索了一下OLED的软件包，还真的有。果断用起来。这个原来是用在arduino上的库已经被大佬移植的好好的了，直接用轮子就好了；而且还提供了example，一些重复代码直接复制粘贴就可以了。</p><p><img src="/2020/12/08/art-pi/20201208231853982.png" alt="在这里插入图片描述"></p><p><img src="/2020/12/08/art-pi/20201208231924281.png" alt="在这里插入图片描述"></p><p>如图配置即可</p><h6 id="在cv过程中遇到的小坑"><a href="#在cv过程中遇到的小坑" class="headerlink" title="在cv过程中遇到的小坑"></a>在cv过程中遇到的小坑</h6><p>仔细观察ART-Pi的板子，就会发现上边没有标注引脚名称……最后找到了<strong>ART-Pi扩展引脚说明.pdf</strong>这个文档</p><p><img src="/2020/12/08/art-pi/20201208232039783.png" alt="在这里插入图片描述"></p><p><img src="/2020/12/08/art-pi/20201208232045905.png" alt="在这里插入图片描述"><br>在这里插入图片描述<br>从上图可以看出PH11、PH12分别是I2C的SCL、SDA。随后，回到rtt-studio打开<code>drv_gpio.c</code>找到PH11、PH12对应的引脚号(如下图所示)。但是这个方法略显麻烦。<br><img src="/2020/12/08/art-pi/20201208232151162.png" alt="在这里插入图片描述"></p><p>由于这是stm32的mcu，所以我们可以直接通过这个<code>GET_PIN(port,pin)</code>这个宏来获取引脚编号，这个宏在<code>drv_common.h</code>中定义：</p><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="meta">#<span class="meta-keyword">define</span> GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN)</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OLED_I2C_PIN_SCL                    123   <span class="comment">// PH11</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OLED_I2C_PIN_SDA                    124   <span class="comment">// PH12</span></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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OLED_I2C_PIN_SCL                    GET_PIN(H,11)   <span class="comment">// PH11</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OLED_I2C_PIN_SDA                    GET_PIN(H,12)   <span class="comment">// PH12</span></span></span><br></pre></td></tr></table></figure><p>值得注意的是使用第二种写法时，一定要添加头文件 <code>#include “drv_common.h”</code>，不然会报错。</p><p>在OLED显示这方面，参考了其他大佬的代码。但是他们的代码都是跑在死循环里边的，一旦使用了就不能用Finsh控制台了，就很烦。我稍微改了一下，加了一个线程并且导出了MSH命令：</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><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;rthw.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;rtthread.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;rtdevice.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;drv_common.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;drv_soft_i2c.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> THREAD_PRIORITY         25</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> THREAD_STACK_SIZE       1024</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> THREAD_TIMESLICE        5</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">rt_thread_t</span> tid1 = RT_NULL;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OLED_I2C_PIN_SCL                    GET_PIN(H,11)   <span class="comment">// PH11</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> OLED_I2C_PIN_SDA                    GET_PIN(H,12)   <span class="comment">// PH12</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> U8G2_SSD1306_128X64_NONAME_F_SW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0,\</span></span></span><br><span class="line"><span class="function"><span class="params">                                         <span class="comment">/* clock=*/</span> OLED_I2C_PIN_SCL,\</span></span></span><br><span class="line"><span class="function"><span class="params">                                         <span class="comment">/* data=*/</span> OLED_I2C_PIN_SDA,\</span></span></span><br><span class="line"><span class="function"><span class="params">                                         <span class="comment">/* reset=*/</span> U8X8_PIN_NONE)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">oled_display</span><span class="params">(<span class="keyword">void</span> *param)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    u8g2.begin();</span><br><span class="line">    u8g2.clearBuffer();</span><br><span class="line"></span><br><span class="line">    u8g2.setFont(u8g2_font_logisoso32_tf);</span><br><span class="line">    u8g2.setCursor(<span class="number">48</span>+<span class="number">3</span>, <span class="number">42</span>);</span><br><span class="line">    u8g2.print(<span class="string">&quot;Hi~&quot;</span>);     <span class="comment">// requires enableUTF8Print()</span></span><br><span class="line"></span><br><span class="line">    u8g2.setFont(u8g2_font_6x13_tr);            <span class="comment">// choose a suitable font</span></span><br><span class="line">    u8g2.drawStr(<span class="number">30</span>, <span class="number">60</span>, <span class="string">&quot;By Sakura&quot;</span>);   <span class="comment">// write something to the internal memory</span></span><br><span class="line">    u8g2.sendBuffer();</span><br><span class="line"></span><br><span class="line">    rt_thread_mdelay(<span class="number">2000</span>);</span><br><span class="line">    <span class="keyword">char</span> mstr[<span class="number">3</span>];</span><br><span class="line">    <span class="keyword">char</span> hstr[<span class="number">3</span>];</span><br><span class="line">    <span class="keyword">time_t</span> now;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">tm</span> *<span class="title">p</span>;</span></span><br><span class="line">    <span class="keyword">int</span> min = <span class="number">0</span>, hour = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        now = time(RT_NULL);</span><br><span class="line">        p=gmtime((<span class="keyword">const</span> <span class="keyword">time_t</span>*) &amp;now);</span><br><span class="line">        hour = p-&gt;tm_hour;</span><br><span class="line">        min = p-&gt;tm_min;</span><br><span class="line">        <span class="built_in">sprintf</span>(mstr, <span class="string">&quot;%02d&quot;</span>, min);</span><br><span class="line">        <span class="built_in">sprintf</span>(hstr, <span class="string">&quot;%02d&quot;</span>, hour);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        u8g2.firstPage();</span><br><span class="line">        <span class="keyword">do</span> &#123;</span><br><span class="line">             u8g2.setFont(u8g2_font_logisoso42_tn);</span><br><span class="line">             u8g2.drawStr(<span class="number">0</span>,<span class="number">63</span>,hstr);</span><br><span class="line">             u8g2.drawStr(<span class="number">50</span>,<span class="number">63</span>,<span class="string">&quot;:&quot;</span>);</span><br><span class="line">             u8g2.drawStr(<span class="number">67</span>,<span class="number">63</span>,mstr);</span><br><span class="line">           &#125;</span><br><span class="line">        <span class="keyword">while</span> ( u8g2.nextPage() );</span><br><span class="line"></span><br><span class="line">        rt_thread_mdelay(<span class="number">50</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="keyword">int</span> <span class="title">thread_sample</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">/* 创建线程 1，名称是 thread1，入口是 thread1_entry*/</span></span><br><span class="line">    tid1 = rt_thread_create(<span class="string">&quot;thread1&quot;</span>,</span><br><span class="line">                            oled_display, RT_NULL,</span><br><span class="line">                            THREAD_STACK_SIZE,</span><br><span class="line">                            THREAD_PRIORITY, THREAD_TIMESLICE);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 如果获得线程控制块，启动这个线程 */</span></span><br><span class="line">    <span class="keyword">if</span> (tid1 != RT_NULL)</span><br><span class="line">        rt_thread_startup(tid1);</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><span class="line"></span><br><span class="line"><span class="comment">/* 导出到 msh 命令列表中 */</span></span><br><span class="line">MSH_CMD_EXPORT(thread_sample, thread sample);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h5><p>先联网。使用的是板载WiFi模块，使用命令 <code>wifi join [SSID] [PASSWORD]</code>连网即可。</p><p><img src="/2020/12/08/art-pi/20201208232231108.png" alt="在这里插入图片描述"></p><p>导出的msh命令列表里边还有个同步网络时间的命令 <code>date</code></p><p><img src="/2020/12/08/art-pi/20201208232302783.png" alt="在这里插入图片描述"></p><p>最后输入 <code>thread_sample</code> ：</p><p><img src="/2020/12/08/art-pi/IMG_20201208_225947.jpg" alt="IMG_20201208_225947"></p><h5 id="遗留问题"><a href="#遗留问题" class="headerlink" title="遗留问题"></a>遗留问题</h5><ol><li><p>这个功能就是一个简单的网络助手。但是从上边的演示过程中，可以看到，需要手动输入命令才能跑起来。这样很不智能啊，但是板载的WiFi模块(AP6212)我在工程中找了半天也没看到关于它的代码在哪儿。有空仔细研究研究，怎么在系统初始化时就连上网络、同步网络时间</p></li><li><p>PH11、PH12的引脚应该是属于硬件iic，但是我配置的是软件iic。这其中会不会有不同目前还没有深究，下回试试其他引脚来模拟iic</p></li></ol>]]></content>
    
    
    <summary type="html">没有创意，只好旧活新整(搬移老工程)</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="RT-Thread" scheme="https://ethereal14.github.io/tags/RT-Thread/"/>
    
  </entry>
  
  <entry>
    <title>一些学习过程中遇到的常用命令</title>
    <link href="https://ethereal14.github.io/2020/12/08/%E4%B8%80%E4%BA%9B%E5%AD%A6%E4%B9%A0%E8%BF%87%E7%A8%8B%E4%B8%AD%E9%81%87%E5%88%B0%E7%9A%84%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
    <id>https://ethereal14.github.io/2020/12/08/%E4%B8%80%E4%BA%9B%E5%AD%A6%E4%B9%A0%E8%BF%87%E7%A8%8B%E4%B8%AD%E9%81%87%E5%88%B0%E7%9A%84%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</id>
    <published>2020-12-08T02:46:13.000Z</published>
    <updated>2023-03-12T16:03:10.205Z</updated>
    
    <content type="html"><![CDATA[<h1 id="一些常用命令"><a href="#一些常用命令" class="headerlink" title="一些常用命令"></a>一些常用命令</h1><h2 id="使用wget下载clangd"><a href="#使用wget下载clangd" class="headerlink" title="使用wget下载clangd"></a>使用wget下载clangd</h2><p>ubuntu2004的软件源安装clangd版本太低，用wget安装，随便还可以使用clang编译器了</p><figure class="highlight shell"><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">sudo mkdir -p /usr/local</span><br><span class="line">cd /usr/local</span><br><span class="line">sudo wget https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz</span><br><span class="line">sudo tar xvf clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz</span><br><span class="line">sudo mv clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04 llvm</span><br><span class="line">export PATH=&quot;$PATH:/usr/local/llvm/bin&quot;</span><br></pre></td></tr></table></figure><h2 id="nfs文件系统命令"><a href="#nfs文件系统命令" class="headerlink" title="nfs文件系统命令"></a>nfs文件系统命令</h2><h3 id="服务端："><a href="#服务端：" class="headerlink" title="服务端："></a>服务端：</h3><h4 id="查看共享文件夹"><a href="#查看共享文件夹" class="headerlink" title="查看共享文件夹"></a>查看共享文件夹</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">showmount -e</span><br></pre></td></tr></table></figure><h4 id="更新nfs"><a href="#更新nfs" class="headerlink" title="更新nfs"></a>更新nfs</h4><p>sudo exportfs -arv</p><h4 id="修改配置文件"><a href="#修改配置文件" class="headerlink" title="修改配置文件"></a>修改配置文件</h4><p>sudo gedit /etc/exports</p><h3 id="客户端："><a href="#客户端：" class="headerlink" title="客户端："></a>客户端：</h3><h4 id="挂载：sudo-mount-t-nfs-192-168-1-101-home-sakura-workdir-mnt"><a href="#挂载：sudo-mount-t-nfs-192-168-1-101-home-sakura-workdir-mnt" class="headerlink" title="挂载：sudo mount -t nfs 192.168.1.101:/home/sakura/workdir /mnt"></a>挂载：sudo mount -t nfs 192.168.1.101:/home/sakura/workdir /mnt</h4><h4 id="查看：showmount-e-192-168-43-27"><a href="#查看：showmount-e-192-168-43-27" class="headerlink" title="查看：showmount -e 192.168.43.27"></a>查看：showmount -e 192.168.43.27</h4><p>  mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 192.168.1.105:/home/sakura/worldir /mnt  </p><h2 id="hexo博客命令"><a href="#hexo博客命令" class="headerlink" title="hexo博客命令"></a>hexo博客命令</h2><table><thead><tr><th>新建操作</th><th></th></tr></thead><tbody><tr><td>新建文章</td><td>hexo n “文章名称”</td></tr><tr><td>新建页面</td><td>hexo n page “页面名称”</td></tr><tr><td></td><td></td></tr></tbody></table><table><thead><tr><th>更新博客</th><th></th><th></th></tr></thead><tbody><tr><td>hexo clean</td><td></td><td></td></tr><tr><td>hexo g</td><td></td><td></td></tr><tr><td>hexo d</td><td></td><td></td></tr><tr><td>hexo g -d</td><td></td><td></td></tr></tbody></table><h2 id="git常用命令-👴实在是记不住）"><a href="#git常用命令-👴实在是记不住）" class="headerlink" title="git常用命令 (👴实在是记不住）"></a>git常用命令 (👴实在是记不住）</h2><table><thead><tr><th>命令</th><th>作用</th><th></th></tr></thead><tbody><tr><td>git add .</td><td>把所有文件加入缓存区</td><td></td></tr><tr><td>git commit -m “commit”</td><td></td><td></td></tr><tr><td>git push</td><td>推送</td><td></td></tr></tbody></table><h2 id="wsl命令"><a href="#wsl命令" class="headerlink" title="wsl命令"></a>wsl命令</h2><p>由于wsl偶尔会启动不了，使用下边儿这个命令就好了。</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netsh winsock reset</span><br></pre></td></tr></table></figure><p>20220118 ，wsl偶尔启动的不了的原因找到拉，是因为我开了游戏加速器。同理，梯子应该也会影响wsl启动。那么docker也应该会受影响</p><h2 id="上传ssh公钥，避免vscode-remote输密码"><a href="#上传ssh公钥，避免vscode-remote输密码" class="headerlink" title="上传ssh公钥，避免vscode-remote输密码"></a>上传ssh公钥，避免vscode-remote输密码</h2><ul><li><p>使用<code>FileZilla</code>直接把<code>id_rsa.pub</code>上传到Linux系统(虚拟机或者服务器)</p></li><li><p>在Linux下边将文件改名即可</p><figure class="highlight shell"><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">mkdir .ssh #没有.ssh文件夹创建即可(在/home/user)</span><br><span class="line">chmod 700 .ssh</span><br><span class="line">cat id_rsa.pub &gt;&gt; .ssh/authorized_keys</span><br><span class="line">chmod 664 authorized_keys</span><br><span class="line">sshd restart</span><br></pre></td></tr></table></figure><p>sshd重启命令更新：<del>sshd restart</del>，</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo /etc/init.d/ssh restart</span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    
    <summary type="html">一些学习过程中遇到的常用命令，比如Linux、hexo、git等</summary>
    
    
    
    <category term="学习" scheme="https://ethereal14.github.io/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="常用命令" scheme="https://ethereal14.github.io/tags/%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
    
  </entry>
  
  <entry>
    <title>RT-Thread内核学习</title>
    <link href="https://ethereal14.github.io/2020/12/08/rt-thread-kernel/"/>
    <id>https://ethereal14.github.io/2020/12/08/rt-thread-kernel/</id>
    <published>2020-12-08T02:31:39.000Z</published>
    <updated>2023-03-12T16:03:10.201Z</updated>
    
    <content type="html"><![CDATA[<h3 id="内核各个文件"><a href="#内核各个文件" class="headerlink" title="内核各个文件"></a>内核各个文件</h3><table><thead><tr><th>文件名</th><th>作用</th></tr></thead><tbody><tr><td>kservice.c</td><td>内核库、提供c库的函数</td></tr><tr><td>object.c</td><td>对象管理</td></tr><tr><td>schedule.c</td><td>实时调度器</td></tr><tr><td>thread.c</td><td>线程管理</td></tr><tr><td>ipc.c</td><td>线程间通信</td></tr><tr><td>clock.c、timer.c</td><td>时钟管理</td></tr><tr><td>mem.c等</td><td>内存管理</td></tr><tr><td>device.c</td><td>设备管理</td></tr></tbody></table><h3 id="RT-Thread程序内存分布"><a href="#RT-Thread程序内存分布" class="headerlink" title="RT-Thread程序内存分布"></a>RT-Thread程序内存分布</h3><ul><li>code：代码段，存放程序代码</li><li>RO-data：只读数据段，存放程序中定义的常量 const；</li><li>RW-data：读写程序段，存放初始化为非0的全局变量 static</li><li>ZI-data：零数据段，存放未初始化的全局变量及初始化为0的变量</li></ul><h3 id="线程管理"><a href="#线程管理" class="headerlink" title="线程管理"></a>线程管理</h3><h4 id="功能特点"><a href="#功能特点" class="headerlink" title="功能特点"></a>功能特点</h4><ol><li>抢占式线程调度器，从就绪列表中找到优先级最高的线程，保证优先级最高的线程能够被运行，最高优先的线程一旦就绪，总能得到CPU的使用权</li><li>一个运行着的线程使一个比它优先级高的线程满足运行条件，就会让出使用权</li><li>中断服务程序使一个高优先级的线程满足运行条件，中断完成时，被中断的线程挂起，优先级高的线程开始运行</li><li>当线程调度器线程切换时，先将当前线程上下文保存起来，当再切回到这个线程时，线程调度器恢复该线程上下文信息</li></ol><h4 id="线程工作机制"><a href="#线程工作机制" class="headerlink" title="线程工作机制"></a>线程工作机制</h4><h5 id="线程控制块"><a href="#线程控制块" class="headerlink" title="线程控制块"></a>线程控制块</h5><p>​        使用<code>struct rt_thread</code>表示，线程控制块是操作系统用于管理线程的数据结构；</p><p>​        存放一些线程信息:优先级、线程名称、线程状态等；</p><p>​        还包含线程间连接的链表结构，事件等集合。</p><h5 id="线程重要属性"><a href="#线程重要属性" class="headerlink" title="线程重要属性"></a>线程重要属性</h5><h6 id="线程栈"><a href="#线程栈" class="headerlink" title="线程栈"></a>线程栈</h6><ul><li>进行线程切换时，会将当前线程的上下文保存在栈中，当线程恢复运行时，再从栈中读取上下文信息，进行恢复</li><li> 线程栈还用于存放函数中的局部变量</li></ul><h6 id="线程状态"><a href="#线程状态" class="headerlink" title="线程状态"></a>线程状态</h6><ul><li>初始状态</li><li>就绪状态</li><li>运行状态</li><li>挂起状态</li><li>关闭状态</li></ul><h6 id="线程优先级"><a href="#线程优先级" class="headerlink" title="线程优先级"></a>线程优先级</h6><ul><li>表示线程被调度的优先程度。</li><li>最大支持256个优先级。在CM系列中，常用32个优先级。</li><li>最低优先级的线程默认分配给空闲线程使用。</li></ul><h6 id="时间片"><a href="#时间片" class="headerlink" title="时间片"></a>时间片</h6><ul><li>每个线程都有时间片，但时间片仅对优先级相同的线程有效。</li><li>系统对优先级相同的就绪状态线程采用时间片轮转的方式调度</li><li>时间片起着约束线程单次运行时长的作用，单位是<code>OS tick</code></li></ul><h6 id="线程入口函数"><a href="#线程入口函数" class="headerlink" title="线程入口函数"></a>线程入口函数</h6><ul><li><p>线程控制块中entry是线程的入口函数,他是线程实现预期功能的函数。线程入口函数有用户设计实现</p><ul><li><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><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">thread_entry</span><span class="params">(<span class="keyword">void</span> * parameter)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">/* 等待时间发生 */</span></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><p>不能进入死循环模式，必须有让出CPU使用权的操作，如：循环中调用延时或者主动挂起。</p></li><li><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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">thread_entry</span><span class="params">(<span class="keyword">void</span>*parameter)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p> 由系统自动删除</p></li></ul><h6 id="线程错误码"><a href="#线程错误码" class="headerlink" title="线程错误码"></a>线程错误码</h6><figure class="highlight cpp"><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="meta">#<span class="meta-keyword">define</span> RT_EOK           0 <span class="comment">/* 无错误     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_ERROR         1 <span class="comment">/* 普通错误     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_ETIMEOUT      2 <span class="comment">/* 超时错误     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_EFULL         3 <span class="comment">/* 资源已满     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_EEMPTY        4 <span class="comment">/* 无资源     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_ENOMEM        5 <span class="comment">/* 无内存     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_ENOSYS        6 <span class="comment">/* 系统不支持     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_EBUSY         7 <span class="comment">/* 系统忙     */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_EIO           8 <span class="comment">/* IO 错误       */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_EINTR         9 <span class="comment">/* 中断系统调用   */</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RT_EINVAL       10 <span class="comment">/* 非法参数      */</span></span></span><br></pre></td></tr></table></figure></li></ul><h5 id="线程状态切换"><a href="#线程状态切换" class="headerlink" title="线程状态切换"></a>线程状态切换</h5><p><img src="/2020/12/08/rt-thread-kernel/rt-thread-kernel/1602053794954.png"></p><ol><li><p>线程通过调用函数 <code>rt_thread_create/init()</code> 进入到初始状态 <code>RT_THREAD_INIT</code>;</p></li><li><p>初始状态的线程通过调用函数 <code>rt_thread_startup()</code> 进入到就绪状态 <code>RT_THREAD_READY</code>;</p></li><li><p>就绪状态的线程被调度器调度后进入运行状态 <code>RT_THREAD_RUNNING</code>;</p></li><li><p>处于运行状态的线程调用 <code>rt_thread_delay()、rt_sem_take()、rt_mutex_take()、rt_mb_rev()</code>等函数或者获取不到资源时，将进入挂起状态 <code>RT_THREAD_SUSPEND</code></p></li><li><p>处于挂起状态的线程，如果等待超时或者未能获得资源或由于其他线程释放了资源，那么他将回到就绪状态。调用 <code>rt_thread_delete/detach()</code>函数，将更改为关闭状态 <code>RT_THREAD_CLOSE</code>;</p></li><li><p>运行状态的线程，如果运行结束，就会在线程的最后部分执行 <code>rt_thread_exit()</code>函数，将状态更改为关闭状态</p></li><li><p><strong>注意！</strong> RT-Thread中实际上不存在运行状态，就绪状态和运行状态是等同的。</p></li></ol><h5 id="系统线程"><a href="#系统线程" class="headerlink" title="系统线程"></a>系统线程</h5><p>系统线程是指由系统创建的线程，用户线程是有用户程序调用线程管理接口创建的线程，在RT-Thread内核中的系统线程有空闲线程与主线程。</p><h6 id="空闲线程"><a href="#空闲线程" class="headerlink" title="空闲线程"></a>空闲线程</h6><p>空闲线程是系统创建的优先级最低的一个线程，永远为就绪状态。</p><p>当系统中无其他就绪线程时，调度器将调度到空闲线程，它通常是个死循环，且永远不被挂起。</p><p>在RTT中有特殊用途：</p><ul><li>若某线程执行完毕，系统将自动删除线程：自动执行 <code>rt_thread_exit()</code>函数，先将该线程从系统就绪队列中删除，再将该线程状态改为关闭状态，不再参与系统调度，然后挂入 <code>rt_thread_defunct</code>僵尸队列(资源未回收，处于关闭状态的线程队列)中，最后空闲线程会回收被删除线程的资源。</li><li>运行用户设置的钩子函数，在空闲线程运行时会调用该钩子函数，适合钩入功耗管理、看门狗喂狗等工作</li></ul><h6 id="主线程"><a href="#主线程" class="headerlink" title="主线程"></a>主线程</h6><ul><li>  系统启动时，系统会创建main线程，入口函数为 <code>main_thread_entry()</code>，用户的应用入口函数<code>main()</code>从这里真正开始，用户可以在 <code>main（）</code>函数中添加自己的初始化代码</li></ul><h4 id="线程管理的方式"><a href="#线程管理的方式" class="headerlink" title="线程管理的方式"></a>线程管理的方式</h4><p>创建动态线程 <code>rt_thread_create()</code>  创建静态线程 <code>rt_thread_init()</code></p><h5 id="创建和删除线程"><a href="#创建和删除线程" class="headerlink" title="创建和删除线程"></a>创建和删除线程</h5><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><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="function"><span class="keyword">rt_thread_t</span> <span class="title">rt_thread_create</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>*name,</span></span></span><br><span class="line"><span class="function"><span class="params">                         <span class="keyword">void</span> (*entry)(<span class="keyword">void</span>* parameter),                          </span></span></span><br><span class="line"><span class="function"><span class="params">                         <span class="keyword">void</span> *parameter,</span></span></span><br><span class="line"><span class="function"><span class="params">                         <span class="keyword">rt_uint32_t</span> stack_size,</span></span></span><br><span class="line"><span class="function"><span class="params">                         <span class="keyword">rt_uint8_t</span> priority,</span></span></span><br><span class="line"><span class="function"><span class="params">                         <span class="keyword">rt_uint32_t</span> tick)</span></span>;</span><br></pre></td></tr></table></figure><p>系统会从动态堆内存中分配一个线程句柄，以及按照参数中指定的栈大小分配相应的空间</p><table><thead><tr><th align="left">参数</th><th>描述</th></tr></thead><tbody><tr><td align="left">name</td><td>线程的名称；线程名称的最大长度由rtconfig.h中的宏RT_NAME_MAX定义，多余部分会自动截掉</td></tr><tr><td align="left">entry</td><td>线程入口函数</td></tr><tr><td align="left">parameter</td><td>线程入口函数参数</td></tr><tr><td align="left">stack_size</td><td>线程栈大小，单位是字节</td></tr><tr><td align="left">priority</td><td>线程的优先级。优先级范围根据系统配置情况(rtconfig.h中的RT_THREAD_PRIORITY_MAX定义),如果支持的是256级优先级，那么范围是从0~255，数值越小优先级越高，0代表最高优先级</td></tr><tr><td align="left">tick</td><td>线程时间片大小。时间片的单位是操作系统的时钟节拍。当系统中存在相同优先级的线程时，这个参数指定线程一次调度能够运行的最大时间长度。这个时间片运行结束时，调度器自动选择下一个就绪态的同优先级线程进行运行</td></tr><tr><td align="left">返回</td><td></td></tr><tr><td align="left">thread</td><td>线程创建成功，返回线程句柄</td></tr><tr><td align="left">RT_NULL</td><td>线程创建失败</td></tr></tbody></table><p>对于使用rt_thread_create()创建出来的线程，当不需要使用，或者运行出错是，可以使用下面的函数接口来从系统中把线程完全删除掉：</p><p><code>rt_err_t rt_thread_delete(rt_thread_t thread)</code></p><p>调用该函数后，线程对象会被移出线程队列，并且从内核对象中删除，释放掉线程占用的堆栈空间，收回来将用于其他内存分配。</p><p><strong>注意：rt_thread_delete()是将thread变为CLOSE状态，放入rt_thread_defunct队列中;真正的删除动作(释放线程和释放线程栈)需要到下一次执行空闲线程时，由空闲线程完成最后的线程删除动作。</strong></p><h5 id="初始化和脱离线程"><a href="#初始化和脱离线程" class="headerlink" title="初始化和脱离线程"></a>初始化和脱离线程</h5>]]></content>
    
    
    <summary type="html">参照官方文档做的笔记</summary>
    
    
    
    <category term="读书笔记" scheme="https://ethereal14.github.io/categories/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="RT-Thread" scheme="https://ethereal14.github.io/tags/RT-Thread/"/>
    
  </entry>
  
</feed>
