緣來來來 宝剑锋从磨砺出,梅花香自苦寒来. http://www.fkomm.cn/feed/緣來來來.zh-hansCopyright© 2018 緣來來來Sat, 19 Jan 2019 17:34:36 +0000Python+树莓派制作IoT(物联网)门控设备http://www.fkomm.cn/article/2019/1/15/65.html<p>今天就和大家分享一个正在制作的物联网开关门监控设备。</p> <p><img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-01-15%20%E4%B8%8B%E5%8D%887.15.06.png" alt=""></p> <p>因为考虑需要在户外使用这套物联网门控设备,所以利用树莓派完成这个设备有两个问题需要解决, 第一是需要解决树莓派和相关模块的供电问题。 第二就是需要户外没有宽带网络情况下的信号传输问题。 只要解决这两个问题那么剩下来的问题就是编程方面的了,针对以上两个问题,这里我们采用比较大众化的方式解决,设备的供电问题我们使用太阳能配合蓄电池进行实现7X24小时供电,信号的传输问题我们使用一块叫做SIM868的通讯模块来实现。下面来介绍一下设备制作的材料准备、制作过程以及程序的编写和调试。</p> <h2>准备材料及工具</h2> <p>1.树莓派(Raspberry Pi 3B+) 数量:1块</p> <p><img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/timg.jpeg" alt=""></p> <p>2.SIM868通讯模块(这里使用的是适配树莓派的微雪电子的SIM868通讯模块) 数量:1块</p> <p><img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-01-15%20%E4%B8%8B%E5%8D%887.15.37.png" alt=""></p> <p>3.电磁感应磁条(常开常闭型) 数量:1组</p> <p>4.SIM868模块外接天线 数量:1根(根据现场安设实际情况确定)</p> <p>5.树莓派T型扩展板 数量:1块</p> <p>6.实验面包板 数量:1块</p> <p>7.杜邦线(公对公,公对母) 数量:若干</p> <p>8.太阳能板 数量:1块</p> <p>9.带保护板的锂电池 数量:2组(根据电池使用的性能情况可适当增加)</p> <p>10.电压电流转换板 数量:1块</p> <p>11.连接电线 数量:(根据现场安设实际情况确定)</p> <p>12.两芯屏蔽线 数量:10米(0.3粗即可根据现场安设实际情况确定)</p> <p>13.防爆箱 (防尘、防雾) 数量:1个(规格根据实际情况确定)</p> <p>14.Micro USB充电线 数量:2根</p> <p>15.SIM卡(移动和联通均可,模块暂不支持电信CDMA) 数量:1张</p> <p>16.电烙铁及焊锡</p> <h2>设备供电及模块链接说明</h2> <ol> <li><p>供电原理:设备的供电依靠太阳能板配合锂电池进行供电,需要一块可以将太阳能板和锂电池的输出电压和电流转换成树莓派和SIM868通讯模块工作电压和电流的转换板,设备供电链接图如图。 <img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-01-15%20%E4%B8%8B%E5%8D%887.18.50.png" alt=""> 实现效果,白天可以通过太阳能负责给树莓派及通讯模块供电并同时给锂电池充电。晚上将由充电完毕的锂电池负责给设备供电。 <img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-01-15%20%E4%B8%8B%E5%8D%887.19.12.png" alt=""></p> </li> <li><p>设备链接:树莓派的GPIO PIN# 2针脚(5V)和 PIN# 23针脚 链接电磁感应模块的引线。负责接收电磁感应模块的开关状态,树莓派的GPIO PIN# 4(5V),PIN# 6(Ground) ,PIN# 8(TX),PIN# 10(RX)分别链接SIM868通讯模块的5V,ground,串口TX和RX,负责实现模块的树莓派与SIM868通讯模块的串口通讯和供电链接,并将信号树莓派的接收到的电磁感应磁条开关信号,通过SIM868通讯模块出输出去(这里采用的是http传输协议,具体实现方法见程序编码部分) <img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/rpi-pins-40-0.png" alt=""></p> </li> </ol> <h2>程序代码</h2> <h3>python程序源码:</h3> <div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">RPi.GPIO</span> <span class="kn">as</span> <span class="nn">GPIO</span> <span class="kn">import</span> <span class="nn">time</span> <span class="kn">import</span> <span class="nn">serial</span> <span class="k">def</span> <span class="nf">gpio_init</span><span class="p">():</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">setwarnings</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">GPIO</span><span class="o">.</span><span class="n">BOARD</span><span class="p">)</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">setup</span><span class="p">(</span><span class="mi">23</span><span class="p">,</span><span class="n">GPIO</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span> <span class="k">def</span> <span class="nf">send_data</span><span class="p">(</span><span class="n">param</span><span class="p">):</span> <span class="n">W_http_6</span><span class="o">=</span><span class="s1">&#39;AT+HTTPPARA=&quot;URL&quot;,&quot;http://**************/iot.php?status=&#39;</span><span class="o">+</span><span class="n">param</span><span class="o">+</span><span class="s1">&#39;&quot;</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_6</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="n">W_http_7</span><span class="o">=</span><span class="s1">&#39;AT+HTTPACTION=0</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_7</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span> <span class="n">ser</span> <span class="o">=</span> <span class="n">serial</span><span class="o">.</span><span class="n">Serial</span><span class="p">(</span><span class="s2">&quot;/dev/ttyS0&quot;</span><span class="p">,</span><span class="mi">115200</span><span class="p">)</span> <span class="n">W_http_1</span><span class="o">=</span><span class="s1">&#39;AT+HTTPTERM</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_1</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_2</span><span class="o">=</span><span class="s1">&#39;AT+SAPBR=3,1,&quot;CONTYPE&quot;,&quot;GPRS&quot;</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_2</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_3</span><span class="o">=</span><span class="s1">&#39;AT+SAPBR=3,1,&quot;APN&quot;,&quot;CMNET&quot;</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_3</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_4</span><span class="o">=</span><span class="s1">&#39;AT+SAPBR=1,1</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_4</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_5</span><span class="o">=</span><span class="s1">&#39;AT+HTTPINIT</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_5</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">gpio_init</span><span class="p">()</span> <span class="n">status</span><span class="o">=</span><span class="mi">1</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="k">if</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">input</span><span class="p">(</span><span class="mi">23</span><span class="p">)</span> <span class="o">==</span> <span class="bp">True</span><span class="p">:</span> <span class="k">if</span> <span class="n">status</span><span class="o">==</span><span class="mi">1</span><span class="p">:</span> <span class="n">send_data</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="n">status</span><span class="o">=</span><span class="mi">2</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;门的状态:关闭&quot;</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">pass</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="n">status</span><span class="o">==</span><span class="mi">2</span><span class="p">:</span> <span class="n">send_data</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">status</span><span class="o">=</span><span class="mi">1</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;门的状态:打开&quot;</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">pass</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">cleanup</span><span class="p">()</span> </pre></div> <h3>php程序源码</h3> <div class="highlight"><pre><span></span><span class="x">require_once(&quot;../../func/dbaccess.php&quot;);</span> <span class="x"> if (doConnect($cn) == false) {</span> <span class="x"> return false;</span> <span class="x"> }</span> <span class="x"> $strSQL = &quot;insert into iot_tbl (position,status,create_time) values (&quot;&#39;.第一号门.&#39;&quot;,&#39;&quot;. $_GET[&#39;status&#39;].&quot;&#39;,now())&quot;;</span> <span class="x"> doInsertUpdate($strSQL);</span> <span class="x"> doClose($cn);</span> </pre></div> <h2>代码解析</h2> <p>这里使用的Python版本号为3.7</p> <div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">RPi.GPIO</span> <span class="kn">as</span> <span class="nn">GPIO</span> <span class="kn">import</span> <span class="nn">time</span> <span class="kn">import</span> <span class="nn">serial</span> </pre></div> <p>引用了python的3个类库GPIO,time以及串口调试库serial,为实现程序的调试可编写,在使用serial串口调试库前,要实现树莓派的串口配置和Linux系统下的串口调试工具minicom的安装。</p> <div class="highlight"><pre><span></span><span class="n">ser</span><span class="o">=</span><span class="n">serial</span><span class="o">.</span><span class="n">Serial</span><span class="p">(</span><span class="s2">&quot;/dev/ttyS0&quot;</span><span class="p">,</span><span class="mi">115200</span><span class="p">)</span> <span class="n">W_http_1</span><span class="o">=</span><span class="s1">&#39;AT+HTTPTERM</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_1</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_2</span><span class="o">=</span><span class="s1">&#39;AT+SAPBR=3,1,&quot;CONTYPE&quot;,&quot;GPRS&quot;</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_2</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_3</span><span class="o">=</span><span class="s1">&#39;AT+SAPBR=3,1,&quot;APN&quot;,&quot;CMNET&quot;</span><span class="se">\r\n</span><span class="s1">&#39;</span><span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_3</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_4</span><span class="o">=</span><span class="s1">&#39;AT+SAPBR=1,1</span><span class="se">\r\n</span><span class="s1">&#39;</span><span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_4</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">W_http_5</span><span class="o">=</span><span class="s1">&#39;AT+HTTPINIT</span><span class="se">\r\n</span><span class="s1">&#39;</span><span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_5</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> </pre></div> <p>以上代码实在通过调用serial库,设置树莓派串口通信的波特率为115200,并使用 ser.write()函数向串口写入可操作SIM868模块进行通讯的AT指令,这里的AT指令是对SIM868进行HTTP通讯前的配置,具体AT指令的含义在这里不再赘述,可自行百度查找。这是使用time.sleep()函数控制程序执行的等待时间,确保串口写入数据成功。</p> <div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">gpio_init</span><span class="p">():</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">setwarnings</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">GPIO</span><span class="o">.</span><span class="n">BOARD</span><span class="p">)</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">setup</span><span class="p">(</span><span class="mi">23</span><span class="p">,</span><span class="n">GPIO</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span> </pre></div> <p>gpio_init()函数是实现对接收电磁感应模块的GPIO PIN#23针脚的初始化配置。</p> <div class="highlight"><pre><span></span><span class="n">status</span><span class="o">=</span><span class="mi">1</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="k">if</span> <span class="n">GPIO</span><span class="o">.</span><span class="n">input</span><span class="p">(</span><span class="mi">23</span><span class="p">)</span> <span class="o">==</span> <span class="bp">True</span><span class="p">:</span> <span class="k">if</span> <span class="n">status</span><span class="o">==</span><span class="mi">1</span><span class="p">:</span> <span class="n">send_data</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="n">status</span><span class="o">=</span><span class="mi">2</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;门的状态:关闭&quot;</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">pass</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="n">status</span><span class="o">==</span><span class="mi">2</span><span class="p">:</span> <span class="n">send_data</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">status</span><span class="o">=</span><span class="mi">1</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;门的状态:打开&quot;</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">pass</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> </pre></div> <p>这里使用status变量初始化门的状态为1表示门已打开,并使用while True循环分割三秒钟(time.sleep(3))检测GPIO PIN#23 号针脚的电流状态,从而判断门的开关状态,并调用send_data()函数进行数据的发送。</p> <div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">send_data</span><span class="p">(</span><span class="n">param</span><span class="p">):</span> <span class="n">W_http_6</span><span class="o">=</span><span class="s1">&#39;AT+HTTPPARA=&quot;URL&quot;,&quot;http://**************/iot.php?status=&#39;</span><span class="o">+</span><span class="n">param</span><span class="o">+</span><span class="s1">&#39;&quot;</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_6</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="n">W_http_7</span><span class="o">=</span><span class="s1">&#39;AT+HTTPACTION=0</span><span class="se">\r\n</span><span class="s1">&#39;</span> <span class="n">ser</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">W_http_7</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> </pre></div> <p>这里将门的状态status变量的值当做参数传送给你个send_data()函数,在添加到HTTP请求的URL中,在服务器端写了个PHP程序iot.php(程序源码j解析如下)用以接收SIM868通讯模块发送过来的HTTP请求,并使用GET的方式获得到HTTP请求URL中传入的status值,并插入到MySQL数据库中。</p> <div class="highlight"><pre><span></span><span class="x">require_once(&quot;../../func/dbaccess.php&quot;);//封装链接操作MySQL数据库的函数 </span> <span class="x">if (doConnect($cn) == false) { //链接数据库</span> <span class="x"> return false; </span> <span class="x">} </span> <span class="x">$strSQL = &quot;insert into iot_tbl (position,status,create_time) values (&quot;&#39;.第一号门.&#39;&quot;,&#39;&quot;.$_GET[&#39;status&#39;].&quot;&#39;,now())&quot;; //将数据插入MySQL数据库的SQL语句</span> <span class="x">doInsertUpdate($strSQL); //执行SQL</span> <span class="x">doClose($cn); //关闭数据库链接</span> </pre></div> <h2>程序拓展</h2> <p>以上程序完成的是对开关门信号的检测、发送和接收数据,属于整个设备接收和处理数据的核心部分,对接收到的数据,还要做进一步的展示,这里我采用了HTML+JQuery+AJAX的方式,并配合在HTML中播放音频文件和刷新开关门状态图表,来动态展示开关门的效果。实现原理是使用AJAX操作PHP程序循环实时读取MySQL数据库,查看当前门的开关状态,并循环局部刷新HTML页面播放音频和刷新html页面图标,对门的开关效果进行动态展示。每个人的需求不同,展示部分的代码就不做说明,也参照上诉方案自行编写。</p> Python TCP Socket的粘包和分包的处理http://www.fkomm.cn/article/2019/1/6/64.html<h2>概述</h2> <p>在进行TCP Socket开发时,都需要处理数据包粘包和分包的情况。本文详细讲解解决该问题的步骤。使用的语言是Python。实际上解决该问题很简单,在应用层下,定义一个协议:消息头部+消息长度+消息正文即可。</p> <p>那什么是粘包和分包呢?</p> <h2>关于分包和粘包</h2> <p>粘包:发送方发送两个字符串”hello”+”world”,接收方却一次性接收到了”helloworld”。</p> <p>分包:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”。</p> <p>虽然socket环境有以上问题,但是TCP传输数据能保证几点:</p> <p>顺序不变。例如发送方发送hello,接收方也一定顺序接收到hello,这个是TCP协议承诺的,因此这点成为我们解决分包、黏包问题的关键。 分割的包中间不会插入其他数据。</p> <p>因此如果要使用socket通信,就一定要自己定义一份协议。目前最常用的协议标准是:消息头部(包头)+ 消息长度 + 消息正文</p> <h2>TCP为什么会分包</h2> <p>TCP是以段(Segment)为单位发送数据的,建立TCP链接后,有一个最大消息长度(MSS)。如果应用层数据包超过MSS,就会把应用层数据包拆分,分成两个段来发送。这个时候接收端的应用层就要拼接这两个TCP包,才能正确处理数据。</p> <p>相关的,路由器有一个MTU( 最大传输单元),一般是1500字节,除去IP头部20字节,留给TCP的就只有MTU-20字节。所以一般TCP的MSS为MTU-20=1460字节。</p> <p>当应用层数据超过1460字节时,TCP会分多个数据包来发送。</p> <blockquote><p>扩展阅读</p> <p>TCP的RFC定义MSS的默认值是536,这是因为 RFC 791里说了任何一个IP设备都得最少接收576尺寸的大小(实际上来说576是拨号的网络的MTU,而576减去IP头的20个字节就是536)。</p> </blockquote> <h2>TCP为什么会粘包</h2> <p>有时候,TCP为了提高网络的利用率,会使用一个叫做Nagle的算法。该算法是指,发送端即使有要发送的数据,如果很少的话,会延迟发送。如果应用层给TCP传送数据很快的话,就会把两个应用层数据包“粘”在一起,TCP最后只发一个TCP数据包给接收端。</p> <h2>开发环境</h2> <ul> <li>Python版本:3.7.0</li> <li>操作系统:macOs 10.14.2</li> </ul> <p>消息头部(包含消息长度) 消息头部不一定只能是一个字节比如0xAA什么的,也可以包含协议版本号,指令等,当然也可以把消息长度合并到消息头部里,唯一的要求是包头长度要固定的,包体则可变长。下面是我自定义的一个包头:</p> <blockquote><p>版本号(ver) 消息长度(bodySize) 指令(cmd)</p> </blockquote> <p>版本号,消息长度,指令数据类型都是无符号32位整型变量,于是这个消息长度固定为4×3=12字节。在Python由于没有类型定义,所以一般是使用struct模块生成包头。示例:</p> <div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">struct</span> <span class="kn">import</span> <span class="nn">json</span> <span class="n">ver</span> <span class="o">=</span> <span class="mi">1</span> <span class="n">body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">hello</span><span class="o">=</span><span class="s2">&quot;world&quot;</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="c1"># {&quot;hello&quot;: &quot;world&quot;}</span> <span class="n">cmd</span> <span class="o">=</span> <span class="mi">101</span> <span class="n">header</span> <span class="o">=</span> <span class="p">[</span><span class="n">ver</span><span class="p">,</span> <span class="n">body</span><span class="o">.</span><span class="fm">__len__</span><span class="p">(),</span> <span class="n">cmd</span><span class="p">]</span> <span class="n">headPack</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;!3I&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">header</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="n">headPack</span><span class="p">)</span> <span class="c1"># b&#39;\x00\x00\x00\x01\x00\x00\x00\x12\x00\x00\x00e&#39;</span> </pre></div> <p>关于用自定义结束符分割数据包 有的人会想用自定义的结束符分割每一个数据包,这样传输数据包时就不需要指定长度甚至也不需要包头了。但是如果这样做,网络传输性能损失非常大,因为每一读取一个字节都要做一次if判断是否是结束符。所以建议还是选择消息头部+消息长度+消息正文这种方式。</p> <p>而且,使用自定义结束符的时候,如果消息正文中出现这个符号,就会把后面的数据截止,这个时候还需要处理符号转义,类比于\r\n的反斜杠。所以非常不建议使用结束符分割数据包。</p> <p>消息正文 消息正文的数据格式可以使用Json格式,这里一般是用来存放独特信息的数据。在下面代码中,我使用{"hello","world"}数据来测试。在Python使用json模块来生成json数据</p> <p>Python示例 下面使用Python代码展示如何处理TCP Socket的粘包和分包。核心在于用一个FIFO队列接收缓冲区dataBuffer和一个小while循环来判断。</p> <p>具体流程是这样的:把从socket读取出来的数据放到dataBuffer后面(入队),然后进入小循环,如果dataBuffer内容长度小于消息长度(bodySize),则跳出小循环继续接收;大于消息长度,则从缓冲区读取包头并获取包体的长度,再判断整个缓冲区是否大于消息头部+消息长度,如果小于则跳出小循环继续接收,如果大于则读取包体的内容,然后处理数据,最后再把这次的消息头部和消息正文从dataBuffer删掉(出队)。</p> <h4>服务器端代码</h4> <div class="highlight"><pre><span></span><span class="c1"># Python Version:3.7.0</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">struct</span> <span class="n">HOST</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span> <span class="n">PORT</span> <span class="o">=</span> <span class="mi">1234</span> <span class="n">dataBuffer</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">()</span> <span class="n">headerSize</span> <span class="o">=</span> <span class="mi">12</span> <span class="n">sn</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">def</span> <span class="nf">dataHandle</span><span class="p">(</span><span class="n">headPack</span><span class="p">,</span> <span class="n">body</span><span class="p">):</span> <span class="k">global</span> <span class="n">sn</span> <span class="n">sn</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;第</span><span class="si">%s</span><span class="s2">个数据包&quot;</span> <span class="o">%</span> <span class="n">sn</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;ver:</span><span class="si">%s</span><span class="s2">, bodySize:</span><span class="si">%s</span><span class="s2">, cmd:</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">headPack</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="n">body</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span> <span class="k">with</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span> <span class="k">as</span> <span class="n">s</span><span class="p">:</span> <span class="n">s</span><span class="o">.</span><span class="n">bind</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">))</span> <span class="n">s</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">conn</span><span class="p">,</span> <span class="n">addr</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">accept</span><span class="p">()</span> <span class="k">with</span> <span class="n">conn</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s1">&#39;Connected by&#39;</span><span class="p">,</span> <span class="n">addr</span><span class="p">)</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="n">data</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span> <span class="k">if</span> <span class="n">data</span><span class="p">:</span> <span class="c1"># 把数据存入缓冲区,类似于push数据</span> <span class="n">dataBuffer</span> <span class="o">+=</span> <span class="n">data</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">dataBuffer</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">headerSize</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;数据包(</span><span class="si">%s</span><span class="s2"> Byte)小于消息头部长度,跳出小循环&quot;</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">dataBuffer</span><span class="p">))</span> <span class="k">break</span> <span class="c1"># 读取包头</span> <span class="c1"># struct中:!代表Network order,3I代表3个unsigned int数据</span> <span class="n">headPack</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;!3I&#39;</span><span class="p">,</span> <span class="n">dataBuffer</span><span class="p">[:</span><span class="n">headerSize</span><span class="p">])</span> <span class="n">bodySize</span> <span class="o">=</span> <span class="n">headPack</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># 分包情况处理,跳出函数继续接收数据</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">dataBuffer</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">headerSize</span><span class="o">+</span><span class="n">bodySize</span> <span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s2">&quot;数据包(</span><span class="si">%s</span><span class="s2"> Byte)不完整(总共</span><span class="si">%s</span><span class="s2"> Byte),跳出小循环&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">dataBuffer</span><span class="p">),</span> <span class="n">headerSize</span><span class="o">+</span><span class="n">bodySize</span><span class="p">))</span> <span class="k">break</span> <span class="c1"># 读取消息正文的内容</span> <span class="n">body</span> <span class="o">=</span> <span class="n">dataBuffer</span><span class="p">[</span><span class="n">headerSize</span><span class="p">:</span><span class="n">headerSize</span><span class="o">+</span><span class="n">bodySize</span><span class="p">]</span> <span class="c1"># 数据处理</span> <span class="n">dataHandle</span><span class="p">(</span><span class="n">headPack</span><span class="p">,</span> <span class="n">body</span><span class="p">)</span> <span class="c1"># 粘包情况的处理</span> <span class="n">dataBuffer</span> <span class="o">=</span> <span class="n">dataBuffer</span><span class="p">[</span><span class="n">headerSize</span><span class="o">+</span><span class="n">bodySize</span><span class="p">:]</span> <span class="c1"># 获取下一个数据包,类似于把数据pop出</span> </pre></div> <h4>测试服务器端的客户端代码</h4> <p>下面附上测试粘包和分包的客户端代码:</p> <div class="highlight"><pre><span></span><span class="c1"># Python Version:3.7.0</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">time</span> <span class="kn">import</span> <span class="nn">struct</span> <span class="kn">import</span> <span class="nn">json</span> <span class="n">host</span> <span class="o">=</span> <span class="s2">&quot;localhost&quot;</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">1234</span> <span class="n">ADDR</span> <span class="o">=</span> <span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span> <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span> <span class="n">client</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">()</span> <span class="n">client</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">ADDR</span><span class="p">)</span> <span class="c1"># 正常数据包定义</span> <span class="n">ver</span> <span class="o">=</span> <span class="mi">1</span> <span class="n">body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">hello</span><span class="o">=</span><span class="s2">&quot;world&quot;</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="n">cmd</span> <span class="o">=</span> <span class="mi">101</span> <span class="n">header</span> <span class="o">=</span> <span class="p">[</span><span class="n">ver</span><span class="p">,</span> <span class="n">body</span><span class="o">.</span><span class="fm">__len__</span><span class="p">(),</span> <span class="n">cmd</span><span class="p">]</span> <span class="n">headPack</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;!3I&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">header</span><span class="p">)</span> <span class="n">sendData1</span> <span class="o">=</span> <span class="n">headPack</span><span class="o">+</span><span class="n">body</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span> <span class="c1"># 分包数据定义</span> <span class="n">ver</span> <span class="o">=</span> <span class="mi">2</span> <span class="n">body</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">hello</span><span class="o">=</span><span class="s2">&quot;world2&quot;</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="n">cmd</span> <span class="o">=</span> <span class="mi">102</span> <span class="n">header</span> <span class="o">=</span> <span class="p">[</span><span class="n">ver</span><span class="p">,</span> <span class="n">body</span><span class="o">.</span><span class="fm">__len__</span><span class="p">(),</span> <span class="n">cmd</span><span class="p">]</span> <span class="n">headPack</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;!3I&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">header</span><span class="p">)</span> <span class="n">sendData2_1</span> <span class="o">=</span> <span class="n">headPack</span><span class="o">+</span><span class="n">body</span><span class="p">[:</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span> <span class="n">sendData2_2</span> <span class="o">=</span> <span class="n">body</span><span class="p">[</span><span class="mi">2</span><span class="p">:]</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span> <span class="c1"># 粘包数据定义</span> <span class="n">ver</span> <span class="o">=</span> <span class="mi">3</span> <span class="n">body1</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">hello</span><span class="o">=</span><span class="s2">&quot;world3&quot;</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="n">body1</span><span class="p">)</span> <span class="n">cmd</span> <span class="o">=</span> <span class="mi">103</span> <span class="n">header</span> <span class="o">=</span> <span class="p">[</span><span class="n">ver</span><span class="p">,</span> <span class="n">body1</span><span class="o">.</span><span class="fm">__len__</span><span class="p">(),</span> <span class="n">cmd</span><span class="p">]</span> <span class="n">headPack1</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;!3I&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">header</span><span class="p">)</span> <span class="n">ver</span> <span class="o">=</span> <span class="mi">4</span> <span class="n">body2</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">hello</span><span class="o">=</span><span class="s2">&quot;world4&quot;</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="n">body2</span><span class="p">)</span> <span class="n">cmd</span> <span class="o">=</span> <span class="mi">104</span> <span class="n">header</span> <span class="o">=</span> <span class="p">[</span><span class="n">ver</span><span class="p">,</span> <span class="n">body2</span><span class="o">.</span><span class="fm">__len__</span><span class="p">(),</span> <span class="n">cmd</span><span class="p">]</span> <span class="n">headPack2</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;!3I&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">header</span><span class="p">)</span> <span class="n">sendData3</span> <span class="o">=</span> <span class="n">headPack1</span><span class="o">+</span><span class="n">body1</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span><span class="o">+</span><span class="n">headPack2</span><span class="o">+</span><span class="n">body2</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span> <span class="c1"># 正常数据包</span> <span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">sendData1</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># 分包测试</span> <span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">sendData2_1</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span> <span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">sendData2_2</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># 粘包测试</span> <span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">sendData3</span><span class="p">)</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">client</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> </pre></div> <p>服务器端打印结果 下面是测试出来的打印结果,可见接收方已经完美的处理粘包和分包问题了。</p> <div class="highlight"><pre><span></span>Connected by <span class="o">(</span><span class="s1">&#39;127.0.0.1&#39;</span>, <span class="m">23297</span><span class="o">)</span> 第1个数据包 ver:1, bodySize:18, cmd:101 <span class="o">{</span><span class="s2">&quot;hello&quot;</span>: <span class="s2">&quot;world&quot;</span><span class="o">}</span> 数据包(0 Byte)小于包头长度,跳出小循环 数据包(14 Byte)不完整(总共31 Byte),跳出小循环 第2个数据包 ver:2, bodySize:19, cmd:102 <span class="o">{</span><span class="s2">&quot;hello&quot;</span>: <span class="s2">&quot;world2&quot;</span><span class="o">}</span> 数据包(0 Byte)小于包头长度,跳出小循环 第3个数据包 ver:3, bodySize:19, cmd:103 <span class="o">{</span><span class="s2">&quot;hello&quot;</span>: <span class="s2">&quot;world3&quot;</span><span class="o">}</span> 第4个数据包 ver:4, bodySize:19, cmd:104 <span class="o">{</span><span class="s2">&quot;hello&quot;</span>: <span class="s2">&quot;world4&quot;</span><span class="o">}</span> </pre></div> <h3>在Twiested框架下处理粘包和分包</h3> <p>其实无论是使用阻塞还是异步socket开发框架,框架本身都会提供一个接收数据的方法提供给开发者,一般来说开发者都要覆写这个方法。下面是在Twidted开发框架处理粘包和分包的示例,只上核心程序:</p> <div class="highlight"><pre><span></span><span class="c1"># Twiested</span> <span class="k">class</span> <span class="nc">MyProtocol</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span> <span class="n">_data_buffer</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">()</span> <span class="c1"># 代码省略</span> <span class="k">def</span> <span class="nf">dataReceived</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Called whenever data is received.&quot;&quot;&quot;</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data_buffer</span> <span class="o">+=</span> <span class="n">data</span> <span class="n">headerSize</span> <span class="o">=</span> <span class="mi">12</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_data_buffer</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">headerSize</span><span class="p">:</span> <span class="k">return</span> <span class="c1"># 读取消息头部</span> <span class="c1"># struct中:!代表Network order,3I代表3个unsigned int数据</span> <span class="n">headPack</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;!3I&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data_buffer</span><span class="p">[:</span><span class="n">headerSize</span><span class="p">])</span> <span class="c1"># 获取消息正文长度</span> <span class="n">bodySize</span> <span class="o">=</span> <span class="n">headPack</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># 分包情况处理</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_data_buffer</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">headerSize</span><span class="o">+</span><span class="n">bodySize</span> <span class="p">:</span> <span class="k">return</span> <span class="c1"># 读取消息正文的内容</span> <span class="n">body</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data_buffer</span><span class="p">[</span><span class="n">headerSize</span><span class="p">:</span><span class="n">headerSize</span><span class="o">+</span><span class="n">bodySize</span><span class="p">]</span> <span class="c1"># 处理数据</span> <span class="bp">self</span><span class="o">.</span><span class="n">dataHandle</span><span class="p">(</span><span class="n">headPack</span><span class="p">,</span> <span class="n">body</span><span class="p">)</span> <span class="c1"># 粘包情况的处理</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data_buffer</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data_buffer</span><span class="p">[</span><span class="n">headerSize</span><span class="o">+</span><span class="n">bodySize</span><span class="p">:]</span> </pre></div> Microsoft SQL Server on Linux破解 2G内存限制http://www.fkomm.cn/article/2019/1/4/63.html<p>今天在阿里云上面安装Microsoft SQL Server on Linux 的Docker,发现了要求宿主机内存大于2G才给安装,由于服务器内存不足,所以就找了好多资料,下面的方法可以完美解决!!!</p> <p>运行的过程中都会有以下是提示:</p> <div class="highlight"><pre><span></span>sqlservr: This program requires a machine with at least <span class="m">2000</span> megabytes of memory. </pre></div> <p>下面就来解决这个问题:</p> <div class="highlight"><pre><span></span><span class="nb">cd</span> /opt/mssql/bin/ <span class="c1"># 进入目录</span> mv sqlservr sqlservr.old <span class="c1"># 保存备份文件</span> python <span class="c1"># 使用python修改内存限制代码</span> &gt;&gt;&gt;oldfile <span class="o">=</span> open<span class="o">(</span><span class="s2">&quot;sqlservr.old&quot;</span>, <span class="s2">&quot;rb&quot;</span><span class="o">)</span>.read<span class="o">()</span> &gt;&gt;&gt;newfile <span class="o">=</span> oldfile.replace<span class="o">(</span><span class="s2">&quot;\x00\x94\x35\x77&quot;</span>, <span class="s2">&quot;\x00\x80\x84\x1e&quot;</span><span class="o">)</span> &gt;&gt;&gt;open<span class="o">(</span><span class="s2">&quot;sqlservr&quot;</span>, <span class="s2">&quot;wb&quot;</span><span class="o">)</span>.write<span class="o">(</span>newfile<span class="o">)</span> &gt;&gt;&gt;exit<span class="o">()</span> </pre></div> <p>修改后,内存限制被缩小为 512 兆字节,下面正常安装即可。</p> 腾讯云服务器添加虚拟内存http://www.fkomm.cn/article/2019/1/2/62.html<p>使用腾讯云服务器也有一段时间了,不过由于对Linux知识了解的比较少,加上服务器稳定性一直都比较好的,所以便很少去折腾服务器。直到最近,站点时常打不开,查了很久的原因,才发现是内存不够导致的<del>~</del></p> <p>用命令free查看内存使用情况,发现swap分区大小为0,原来腾讯云主机默认是没有划分swap分区的。</p> <p>所以由于我的服务器物理内存本身就很少,而且又没设置swap分区,运行效果可想而知,稍有点并发量、或者恶意用户探测访问等,网站就很容易卡壳了。</p> <p>swap是用来做虚拟内存的。虽然swap无法代替物理内存,但不可缺少。</p> <p>swap分区作用:当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap空间中,等到那些程序要运行时,再从Swap中恢复保存的数据到内存中。这样,系统总是在物理内存不够时,才进行Swap交换。</p> <h3>建立swap的两种方法</h3> <ol> <li>建立分区;</li> <li>创建交换文件。</li> </ol> <p>运行速度:</p> <p>物理内存 &gt; swap分区 &gt; swap文件。</p> <blockquote><p>当你的数据盘已经装了很多内容,不方便重新规划的话,也只好使用swap文件了。像我由于只有一块磁盘,而且磁盘已经装了不少内容,所以就没有选择磁盘格式化,而是选择创建swap文件。</p> </blockquote> <h3>下面介绍创建swap文件的方法:</h3> <h4>创建swap文件</h4> <p>首先,选择你swap文件要放置的位置,比如直接在根目录/ 下创建或者选择一个目录,如/opt。比如我直接在根目录下创建,然后设置swap分区的名称为swapfile:</p> <ol> <li><p>定义swap的大小及位置</p> <div class="highlight"><pre><span></span><span class="o">[</span>root@VM_0_10_centos ~<span class="o">]</span><span class="c1"># cd / </span> <span class="o">[</span>root@VM_0_10_centos /<span class="o">]</span><span class="c1"># dd if=/dev/zero of=/swapfile bs=1k count=2048000</span> </pre></div> <p>上面swapfile为你创建swap文件分区的名称,你可以根据需要改成你自己的名称;bs 即blocksizes,每个块大小为1k;count=2048000,总大小为2G的文件。因为建立swap分区大小的标准一般为物理内存的两倍,而我的内存是1G,所以我选择swap文件大小为2G,当然,也要考虑你硬盘剩余容量的大小。我的硬盘还剩15G,所以再划分2G给swap文件绰绰有余。如果你的内存是0.5G,那么count大小可以选择1024000(1G)。</p> </li> <li><p>建立swap</p> <div class="highlight"><pre><span></span><span class="o">[</span>root@VM_0_10_centos /<span class="o">]</span><span class="c1"># mkswap /swapfile</span> </pre></div> </li> <li><p>启动swap</p> <div class="highlight"><pre><span></span><span class="o">[</span>root@VM_0_10_centos /<span class="o">]</span><span class="c1"># swapon /swapfile</span> </pre></div> </li> <li><p>检查是否正确</p> <div class="highlight"><pre><span></span><span class="o">[</span>root@VM_0_10_centos /<span class="o">]</span><span class="c1"># free -m</span> total used free shared buff/cache available Mem: <span class="m">1838</span> <span class="m">600</span> <span class="m">65</span> <span class="m">2</span> <span class="m">1172</span> <span class="m">1043</span> Swap: <span class="m">1999</span> <span class="m">0</span> <span class="m">1999</span> </pre></div> <p>或者使用swapon -s 命令查看:</p> <div class="highlight"><pre><span></span><span class="o">[</span>root@VM_0_10_centos /<span class="o">]</span><span class="c1"># swapon -s</span> 文件名 类型 大小 已用 权限 /swapfile file <span class="m">2047996</span> <span class="m">0</span> -1 </pre></div> <p>上面的Swap和/swapfile都分别能看到总容量大小,使用了多少。</p> </li> <li><p>设置开机时自启用swap分区 修改/etc/fstab使其启动时自动mount,这个操作与swap分区法一样,在/etc/fstab中最后一行增加如下语句:</p> <div class="highlight"><pre><span></span>/swapfile swap swap defaults <span class="m">0</span> <span class="m">0</span> </pre></div> <p>添加方法可以用vi进行编辑,或者直接echo添加:</p> <div class="highlight"><pre><span></span><span class="o">[</span>root@VM_0_10_centos /<span class="o">]</span><span class="c1"># echo &quot;/swapfile swap swap defaults 0 0&quot; &gt;&gt;/etc/fstab</span> </pre></div> <blockquote><p>注: /swapfile 路径可以修改,可以根据创建的swap文件具体路径来配置。</p> </blockquote> </li> </ol> <h4>删除swap分区</h4> <p>如果不再需要swap,可以清理该分区:</p> <div class="highlight"><pre><span></span><span class="o">[</span>root@VM_0_10_centos /<span class="o">]</span><span class="c1"># swapoff /swapfile</span> </pre></div> 战舰V3 USART1、USART2、UASRT3、UART4、UART5串口配置http://www.fkomm.cn/article/2018/12/22/61.html<h2>摘要</h2> <p>在STM32中UART和USART是不相同的,在官方的文档中,大部分配置的都是USART2和UASRT3,对于UART4和UART5却很少有人配置,由于最近在集成项目,所以要用到多种串口,所以索性就配置了UART4和UART5</p> <h2>区别</h2> <h3>USATR1 和 USATR2,USATR3,UATR4,UATR5 挂载的时钟不一样,第一个挂载在 APB2 上,其余四个挂载在 APB1 上</h3> <p><img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/20161024153238224.png" alt=""></p> <p>例如:</p> <div class="highlight"><pre><span></span><span class="n">RCC_APB2PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB2Periph_USART1</span><span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//USART1 时钟配置</span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_USART2</span><span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//USART2</span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_USART3</span><span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//USART3 </span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_UART4</span> <span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//UART4 </span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_UART5</span> <span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//UART5</span> </pre></div> <ul> <li>USART是通用同步/异步串行接收/发送器</li> <li>UART是通用异步收发传输器</li> </ul> <p>简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是UART。</p> <p>USART支持同步模式,因此USART需要同步时钟信号USART_CK(如STM32 单片机),通常情况同步信号很少使用,因此一般的单片机UART和USART使用方式是一样的,都使用异步模式。</p> <p>UART需要固定的波特率,就是说两位数据的间隔要相等。 UART总线是异步串口,一般由波特率产生器(产生的波特率等于传输波特率的16倍)、UART接收器、UART发送器组成,硬件上有两根线,一根用于发送,一根用于接收。 显然,如果用通用IO口模拟UART总线,则需一个输入口,一个输出口。</p> <p>UART是一个并行输入成为串行输出的芯片,通常集成在主板上,多数是16550AFN芯片。因为计算机内部采用并行数据,不能直接把数据发到Modem,必须经过UART整理才能进行异步传输,其过程为:CPU先把准备写入串行设备的数据放到UART的寄存器(临时内存块)中,再通过FIFO(First Input First Output,先入先出队列)传送到串行设备,若是没有FIFO,信息将变得杂乱无章,不可能传送到Modem。</p> <p>作为接口的一部分,UART还提供以下功能:将由计算机内部传送过来的并行数据转换为输出的串行数据流。将计算机外部来的串行数据转换为字节,供计算机内部使用并行数据的器件使用。在输出的串行数据流中加入奇偶校验位,并对从外部接收的数据流进行奇偶校验。在输出数据流中加入启停标记,并从接收数据流中删除启停标记。处理由键盘或鼠标发出的中断信号(键盘和鼠标也是串行设备)。可以处理计算机与外部串行设备的同步管理问题。</p> <p>USART收发模块一般分为三大部分:时钟发生器、数据发送器和接收器。控制寄存器为所有的模块共享。时钟发生器由同步逻辑电路(在同步从模式下由外部时钟输入驱动)和波特率发生器组成。发送时钟引脚XCK仅用于同步发送模式下,发送器部分由一个单独的写入缓冲器(发送UDR)、一个串行移位寄存器、校验位发生器和用于处理不同浈结构的控制逻辑电路构成。使用写入缓冲器,实现了连续发送多浈数据无延时的通信。接收器是USART模块最复杂的部分,最主要的是时钟和数据接收单元。数据接收单元用作异步数据的接收。除了接收单元,接收器还包括校验位校验器、控制逻辑、移位寄存器和两级接收缓冲器(接收UDR)。接收器支持与发送器相同的帧结构,同时支持桢错误、数据溢出和校验错误的检测。USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备。</p> <p>综上可以看出,USART相对UART来说是在异步通信的基础上还有同步的功能,USART能够提供主动时钟。</p> <h2>配置</h2> <p>先来看一下引脚图</p> <p><img src="https://fkomm-1256750115.cos.ap-shanghai.myqcloud.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202018-12-22%20%E4%B8%8B%E5%8D%884.03.35.png" alt=""></p> <p>可以看到USART1、USART2、UASRT3、UART4、UART5对应的引脚,下面我们就来配置!</p> <h3>USART的配置</h3> <h4>USART1的配置</h4> <p>初始化程序:</p> <div class="highlight"><pre><span></span><span class="c1">//初始化IO 串口1 </span> <span class="c1">//bound:波特率</span> <span class="kt">void</span> <span class="nf">uart_init</span><span class="p">(</span><span class="n">u32</span> <span class="n">bound</span><span class="p">){</span> <span class="c1">//GPIO端口设置</span> <span class="n">GPIO_InitTypeDef</span> <span class="n">GPIO_InitStructure</span><span class="p">;</span> <span class="n">USART_InitTypeDef</span> <span class="n">USART_InitStructure</span><span class="p">;</span> <span class="n">NVIC_InitTypeDef</span> <span class="n">NVIC_InitStructure</span><span class="p">;</span> <span class="n">RCC_APB2PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB2Periph_USART1</span><span class="o">|</span><span class="n">RCC_APB2Periph_GPIOA</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//使能USART1,GPIOA时钟</span> <span class="n">USART_DeInit</span><span class="p">(</span><span class="n">USART1</span><span class="p">);</span> <span class="c1">//复位串口1</span> <span class="c1">//USART1_TX PA.9</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_9</span><span class="p">;</span> <span class="c1">//PA.9</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Speed</span> <span class="o">=</span> <span class="n">GPIO_Speed_50MHz</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_AF_PP</span><span class="p">;</span> <span class="c1">//复用推挽输出</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOA</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PA9</span> <span class="c1">//USART1_RX PA.10</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_10</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_IN_FLOATING</span><span class="p">;</span><span class="c1">//浮空输入</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOA</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PA10</span> <span class="c1">//Usart1 NVIC 配置</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannel</span> <span class="o">=</span> <span class="n">USART1_IRQn</span><span class="p">;</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelPreemptionPriority</span><span class="o">=</span><span class="mi">3</span> <span class="p">;</span><span class="c1">//抢占优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelSubPriority</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">//子优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelCmd</span> <span class="o">=</span> <span class="n">ENABLE</span><span class="p">;</span> <span class="c1">//IRQ通道使能</span> <span class="n">NVIC_Init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">NVIC_InitStructure</span><span class="p">);</span> <span class="c1">//根据指定的参数初始化VIC寄存器</span> <span class="c1">//USART 初始化设置</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_BaudRate</span> <span class="o">=</span> <span class="n">bound</span><span class="p">;</span><span class="c1">//一般设置为9600;</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_WordLength</span> <span class="o">=</span> <span class="n">USART_WordLength_8b</span><span class="p">;</span><span class="c1">//字长为8位数据格式</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_StopBits</span> <span class="o">=</span> <span class="n">USART_StopBits_1</span><span class="p">;</span><span class="c1">//一个停止位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Parity</span> <span class="o">=</span> <span class="n">USART_Parity_No</span><span class="p">;</span><span class="c1">//无奇偶校验位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_HardwareFlowControl</span> <span class="o">=</span> <span class="n">USART_HardwareFlowControl_None</span><span class="p">;</span><span class="c1">//无硬件数据流控制</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Mode</span> <span class="o">=</span> <span class="n">USART_Mode_Rx</span> <span class="o">|</span> <span class="n">USART_Mode_Tx</span><span class="p">;</span> <span class="c1">//收发模式</span> <span class="n">USART_Init</span><span class="p">(</span><span class="n">USART1</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">USART_InitStructure</span><span class="p">);</span> <span class="c1">//初始化串口</span> <span class="n">USART_ITConfig</span><span class="p">(</span><span class="n">USART1</span><span class="p">,</span> <span class="n">USART_IT_RXNE</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span><span class="c1">//开启中断</span> <span class="n">USART_Cmd</span><span class="p">(</span><span class="n">USART1</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//使能串口 </span> <span class="p">}</span> </pre></div> <h4>USART2的配置</h4> <p>初始化程序:</p> <div class="highlight"><pre><span></span><span class="c1">//初始化IO 串口2</span> <span class="c1">//pclk1:PCLK1时钟频率(Mhz)</span> <span class="c1">//bound:波特率 </span> <span class="kt">void</span> <span class="nf">USART2_Init</span><span class="p">(</span><span class="n">u32</span> <span class="n">bound</span><span class="p">)</span> <span class="p">{</span> <span class="n">NVIC_InitTypeDef</span> <span class="n">NVIC_InitStructure</span><span class="p">;</span> <span class="n">GPIO_InitTypeDef</span> <span class="n">GPIO_InitStructure</span><span class="p">;</span> <span class="n">USART_InitTypeDef</span> <span class="n">USART_InitStructure</span><span class="p">;</span> <span class="n">RCC_APB2PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB2Periph_GPIOA</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">// GPIOA时钟</span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_USART2</span><span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="n">USART_DeInit</span><span class="p">(</span><span class="n">USART2</span><span class="p">);</span> <span class="c1">//复位串口2</span> <span class="c1">//USART2_TX PA.2</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_2</span><span class="p">;</span> <span class="c1">//PA.2</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Speed</span> <span class="o">=</span> <span class="n">GPIO_Speed_50MHz</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_AF_PP</span><span class="p">;</span> <span class="c1">//复用推挽输出</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOA</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PA2</span> <span class="c1">//USART2_RX PA.3</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_3</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_IN_FLOATING</span><span class="p">;</span><span class="c1">//浮空输入</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOA</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PA3</span> <span class="c1">//Usart2 NVIC 配置</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannel</span> <span class="o">=</span> <span class="n">USART2_IRQn</span><span class="p">;</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelPreemptionPriority</span><span class="o">=</span><span class="mi">3</span> <span class="p">;</span><span class="c1">//抢占优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelSubPriority</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">//子优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelCmd</span> <span class="o">=</span> <span class="n">ENABLE</span><span class="p">;</span> <span class="c1">//IRQ通道使能</span> <span class="n">NVIC_Init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">NVIC_InitStructure</span><span class="p">);</span> <span class="c1">//根据指定的参数初始化VIC寄存器</span> <span class="c1">//USART 初始化设置</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_BaudRate</span> <span class="o">=</span> <span class="n">bound</span><span class="p">;</span><span class="c1">//一般设置为9600;</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_WordLength</span> <span class="o">=</span> <span class="n">USART_WordLength_8b</span><span class="p">;</span><span class="c1">//字长为8位数据格式</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_StopBits</span> <span class="o">=</span> <span class="n">USART_StopBits_1</span><span class="p">;</span><span class="c1">//一个停止位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Parity</span> <span class="o">=</span> <span class="n">USART_Parity_No</span><span class="p">;</span><span class="c1">//无奇偶校验位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_HardwareFlowControl</span> <span class="o">=</span> <span class="n">USART_HardwareFlowControl_None</span><span class="p">;</span><span class="c1">//无硬件数据流控制</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Mode</span> <span class="o">=</span> <span class="n">USART_Mode_Rx</span> <span class="o">|</span> <span class="n">USART_Mode_Tx</span><span class="p">;</span> <span class="c1">//收发模式</span> <span class="n">USART_Init</span><span class="p">(</span><span class="n">USART2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">USART_InitStructure</span><span class="p">);</span> <span class="c1">//初始化串口</span> <span class="n">USART_ITConfig</span><span class="p">(</span><span class="n">USART2</span><span class="p">,</span> <span class="n">USART_IT_RXNE</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span><span class="c1">//开启中断</span> <span class="n">USART_Cmd</span><span class="p">(</span><span class="n">USART2</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//使能串口 </span> <span class="p">}</span> </pre></div> <h4>USART3的配置</h4> <p>初始化程序:</p> <div class="highlight"><pre><span></span><span class="c1">//初始化IO 串口3</span> <span class="c1">//bound:波特率 </span> <span class="kt">void</span> <span class="nf">USART3_Init</span><span class="p">(</span><span class="n">u32</span> <span class="n">bound</span><span class="p">)</span> <span class="p">{</span> <span class="n">NVIC_InitTypeDef</span> <span class="n">NVIC_InitStructure</span><span class="p">;</span> <span class="n">GPIO_InitTypeDef</span> <span class="n">GPIO_InitStructure</span><span class="p">;</span> <span class="n">USART_InitTypeDef</span> <span class="n">USART_InitStructure</span><span class="p">;</span> <span class="n">RCC_APB2PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB2Periph_GPIOB</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">// GPIOB时钟</span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_USART3</span><span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="n">USART_DeInit</span><span class="p">(</span><span class="n">USART3</span><span class="p">);</span> <span class="c1">//复位串口3</span> <span class="c1">//USART3_TX PB.10</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_10</span><span class="p">;</span> <span class="c1">//PB.10</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Speed</span> <span class="o">=</span> <span class="n">GPIO_Speed_50MHz</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_AF_PP</span><span class="p">;</span> <span class="c1">//复用推挽输出</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOB</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PB10</span> <span class="c1">//USART2_RX PB.11</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_11</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_IN_FLOATING</span><span class="p">;</span><span class="c1">//浮空输入</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOB</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PB11</span> <span class="c1">//Usart3 NVIC 配置</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannel</span> <span class="o">=</span> <span class="n">USART3_IRQn</span><span class="p">;</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelPreemptionPriority</span><span class="o">=</span><span class="mi">3</span> <span class="p">;</span><span class="c1">//抢占优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelSubPriority</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">//子优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelCmd</span> <span class="o">=</span> <span class="n">ENABLE</span><span class="p">;</span> <span class="c1">//IRQ通道使能</span> <span class="n">NVIC_Init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">NVIC_InitStructure</span><span class="p">);</span> <span class="c1">//根据指定的参数初始化VIC寄存器</span> <span class="c1">//USART 初始化设置</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_BaudRate</span> <span class="o">=</span> <span class="n">bound</span><span class="p">;</span><span class="c1">//一般设置为9600;</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_WordLength</span> <span class="o">=</span> <span class="n">USART_WordLength_8b</span><span class="p">;</span><span class="c1">//字长为8位数据格式</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_StopBits</span> <span class="o">=</span> <span class="n">USART_StopBits_1</span><span class="p">;</span><span class="c1">//一个停止位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Parity</span> <span class="o">=</span> <span class="n">USART_Parity_No</span><span class="p">;</span><span class="c1">//无奇偶校验位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_HardwareFlowControl</span> <span class="o">=</span> <span class="n">USART_HardwareFlowControl_None</span><span class="p">;</span><span class="c1">//无硬件数据流控制</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Mode</span> <span class="o">=</span> <span class="n">USART_Mode_Rx</span> <span class="o">|</span> <span class="n">USART_Mode_Tx</span><span class="p">;</span> <span class="c1">//收发模式</span> <span class="n">USART_Init</span><span class="p">(</span><span class="n">USART3</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">USART_InitStructure</span><span class="p">);</span> <span class="c1">//初始化串口</span> <span class="n">USART_ITConfig</span><span class="p">(</span><span class="n">USART3</span><span class="p">,</span> <span class="n">USART_IT_RXNE</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span><span class="c1">//开启中断</span> <span class="n">USART_Cmd</span><span class="p">(</span><span class="n">USART3</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//使能串口 </span> <span class="p">}</span> </pre></div> <h3>UART的配置</h3> <h4>UART4的配置</h4> <p>初始化程序:</p> <div class="highlight"><pre><span></span><span class="c1">//初始化IO 串口4 </span> <span class="c1">//bound:波特率</span> <span class="kt">void</span> <span class="nf">uart4_init</span><span class="p">(</span><span class="n">u32</span> <span class="n">bound</span><span class="p">){</span> <span class="c1">//GPIO端口设置</span> <span class="n">GPIO_InitTypeDef</span> <span class="n">GPIO_InitStructure</span><span class="p">;</span> <span class="n">USART_InitTypeDef</span> <span class="n">USART_InitStructure</span><span class="p">;</span> <span class="n">NVIC_InitTypeDef</span> <span class="n">NVIC_InitStructure</span><span class="p">;</span> <span class="n">RCC_APB2PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB2Periph_GPIOC</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">// GPIO时钟</span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_UART4</span><span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="n">USART_DeInit</span><span class="p">(</span><span class="n">UART4</span><span class="p">);</span> <span class="c1">//复位串口4</span> <span class="c1">//UART4_TX PC.10</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_10</span><span class="p">;</span> <span class="c1">//PC.10</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Speed</span> <span class="o">=</span> <span class="n">GPIO_Speed_50MHz</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_AF_PP</span><span class="p">;</span> <span class="c1">//复用推挽输出</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PC10</span> <span class="c1">//UART4_RX PC.11</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_11</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_IN_FLOATING</span><span class="p">;</span><span class="c1">//浮空输入</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PC11</span> <span class="c1">//Uart4 NVIC 配置</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannel</span> <span class="o">=</span> <span class="n">UART4_IRQn</span><span class="p">;</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelPreemptionPriority</span><span class="o">=</span><span class="mi">3</span> <span class="p">;</span><span class="c1">//抢占优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelSubPriority</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">//子优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelCmd</span> <span class="o">=</span> <span class="n">ENABLE</span><span class="p">;</span> <span class="c1">//IRQ通道使能</span> <span class="n">NVIC_Init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">NVIC_InitStructure</span><span class="p">);</span> <span class="c1">//根据指定的参数初始化VIC寄存器</span> <span class="c1">//USART 初始化设置</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_BaudRate</span> <span class="o">=</span> <span class="n">bound</span><span class="p">;</span><span class="c1">//一般设置为9600;</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_WordLength</span> <span class="o">=</span> <span class="n">USART_WordLength_8b</span><span class="p">;</span><span class="c1">//字长为8位数据格式</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_StopBits</span> <span class="o">=</span> <span class="n">USART_StopBits_1</span><span class="p">;</span><span class="c1">//一个停止位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Parity</span> <span class="o">=</span> <span class="n">USART_Parity_No</span><span class="p">;</span><span class="c1">//无奇偶校验位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_HardwareFlowControl</span> <span class="o">=</span> <span class="n">USART_HardwareFlowControl_None</span><span class="p">;</span><span class="c1">//无硬件数据流控制</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Mode</span> <span class="o">=</span> <span class="n">USART_Mode_Rx</span> <span class="o">|</span> <span class="n">USART_Mode_Tx</span><span class="p">;</span> <span class="c1">//收发模式</span> <span class="n">USART_Init</span><span class="p">(</span><span class="n">UART4</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">USART_InitStructure</span><span class="p">);</span> <span class="c1">//初始化串口</span> <span class="n">USART_ITConfig</span><span class="p">(</span><span class="n">UART4</span><span class="p">,</span> <span class="n">USART_IT_RXNE</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span><span class="c1">//开启中断</span> <span class="n">USART_Cmd</span><span class="p">(</span><span class="n">UART4</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//使能串口 </span> <span class="p">}</span> </pre></div> <h4>UART5的配置</h4> <p>初始化程序:</p> <div class="highlight"><pre><span></span><span class="c1">//初始化IO 串口5</span> <span class="c1">//bound:波特率</span> <span class="kt">void</span> <span class="nf">uart5_init</span><span class="p">(</span><span class="n">u32</span> <span class="n">bound</span><span class="p">){</span> <span class="c1">//GPIO端口设置</span> <span class="n">GPIO_InitTypeDef</span> <span class="n">GPIO_InitStructure</span><span class="p">;</span> <span class="n">USART_InitTypeDef</span> <span class="n">USART_InitStructure</span><span class="p">;</span> <span class="n">NVIC_InitTypeDef</span> <span class="n">NVIC_InitStructure</span><span class="p">;</span> <span class="n">RCC_APB2PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB2Periph_GPIOC</span><span class="o">|</span><span class="n">RCC_APB2Periph_GPIOD</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">// GPIO时钟</span> <span class="n">RCC_APB1PeriphClockCmd</span><span class="p">(</span><span class="n">RCC_APB1Periph_UART4</span><span class="p">,</span><span class="n">ENABLE</span><span class="p">);</span> <span class="n">USART_DeInit</span><span class="p">(</span><span class="n">UART5</span><span class="p">);</span> <span class="c1">//复位串口5</span> <span class="c1">//UART5_TX PC.12</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_12</span><span class="p">;</span> <span class="c1">//PC.12</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Speed</span> <span class="o">=</span> <span class="n">GPIO_Speed_50MHz</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_AF_PP</span><span class="p">;</span> <span class="c1">//复用推挽输出</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PC10</span> <span class="c1">//UART5_RX PD.2</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Pin</span> <span class="o">=</span> <span class="n">GPIO_Pin_2</span><span class="p">;</span> <span class="n">GPIO_InitStructure</span><span class="p">.</span><span class="n">GPIO_Mode</span> <span class="o">=</span> <span class="n">GPIO_Mode_IN_FLOATING</span><span class="p">;</span><span class="c1">//浮空输入</span> <span class="n">GPIO_Init</span><span class="p">(</span><span class="n">GPIOD</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">GPIO_InitStructure</span><span class="p">);</span> <span class="c1">//初始化PD2</span> <span class="c1">//Uart5 NVIC 配置</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannel</span> <span class="o">=</span> <span class="n">UART5_IRQn</span><span class="p">;</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelPreemptionPriority</span><span class="o">=</span><span class="mi">3</span> <span class="p">;</span><span class="c1">//抢占优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelSubPriority</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">//子优先级3</span> <span class="n">NVIC_InitStructure</span><span class="p">.</span><span class="n">NVIC_IRQChannelCmd</span> <span class="o">=</span> <span class="n">ENABLE</span><span class="p">;</span> <span class="c1">//IRQ通道使能</span> <span class="n">NVIC_Init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">NVIC_InitStructure</span><span class="p">);</span> <span class="c1">//根据指定的参数初始化VIC寄存器</span> <span class="c1">//USART 初始化设置</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_BaudRate</span> <span class="o">=</span> <span class="n">bound</span><span class="p">;</span><span class="c1">//一般设置为9600;</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_WordLength</span> <span class="o">=</span> <span class="n">USART_WordLength_8b</span><span class="p">;</span><span class="c1">//字长为8位数据格式</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_StopBits</span> <span class="o">=</span> <span class="n">USART_StopBits_1</span><span class="p">;</span><span class="c1">//一个停止位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Parity</span> <span class="o">=</span> <span class="n">USART_Parity_No</span><span class="p">;</span><span class="c1">//无奇偶校验位</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_HardwareFlowControl</span> <span class="o">=</span> <span class="n">USART_HardwareFlowControl_None</span><span class="p">;</span><span class="c1">//无硬件数据流控制</span> <span class="n">USART_InitStructure</span><span class="p">.</span><span class="n">USART_Mode</span> <span class="o">=</span> <span class="n">USART_Mode_Rx</span> <span class="o">|</span> <span class="n">USART_Mode_Tx</span><span class="p">;</span> <span class="c1">//收发模式</span> <span class="n">USART_Init</span><span class="p">(</span><span class="n">UART5</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">USART_InitStructure</span><span class="p">);</span> <span class="c1">//初始化串口</span> <span class="n">USART_ITConfig</span><span class="p">(</span><span class="n">UART5</span><span class="p">,</span> <span class="n">USART_IT_RXNE</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span><span class="c1">//开启中断</span> <span class="n">USART_Cmd</span><span class="p">(</span><span class="n">UART5</span><span class="p">,</span> <span class="n">ENABLE</span><span class="p">);</span> <span class="c1">//使能串口 </span> <span class="p">}</span> </pre></div> <p>对比一下不难发现UASRT的初始化和UART的初始化几乎相同!!!!!</p>