<div id="article_content" class="article_content">
<h1 align="center"><a name="t0"></a><span style="font-size:18px"><span style="font-family:Calibri">LWIP</span>使用經驗</span></h1>
<h2><a name="t1"></a><span style="font-size:18px">一<span style="font-family:Cambria"> LWIP</span>記憶體管理</span></h2>
<p><span style="font-size:18px"><span style="font-family:Calibri">LWIP</span>的記憶體管理使用了<span style="font-family:Calibri">2</span>種方式:記憶體池<span style="font-family:Calibri">memp</span>和記憶體堆<span style="font-family:Calibri">mem</span>,如圖<span style="font-family:Calibri">1</span>所示。</span></p>
<p><span style="font-size:18px">記憶體池的特點是預先開辟多組固定大小的記憶體塊組織成連結清單,實作簡單,配置設定和回收速度快,不會産生記憶體碎片,但是大小固定,并且需要預估算準确。</span></p>
<p><span style="font-size:18px">記憶體堆的本質是對一個事先定義好的記憶體塊進行合理有效的組織和管理,主要用于任意大小的記憶體配置設定,實作較複雜,配置設定需要查找,回收需要合并,容易産生記憶體碎片,需要合理估算記憶體堆的總大小。</span></p>
<p></p>
<p align="center"><span style="font-size:18px"> </span></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517103926406" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">1</span>記憶體池與記憶體堆</span></p>
<h3><a name="t2"></a><span style="font-size:18px"><span style="font-family:Calibri">1.</span> 資料包管理</span></h3>
<p><span style="font-size:18px">資料包管理結構<span style="font-family:Calibri">pbuf</span>共有四種類型,它們的特點和使用場合如表<span style="font-family:Calibri">1</span>所示。</span></p>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top">
<p><span style="font-size:18px">類别</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">配置設定方式</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">特點</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">使用場合</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p><span style="font-family:Calibri"><span style="font-size:18px">PBUF_RAM</span></span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">記憶體堆,包括<span style="font-family:Calibri">pbuf</span>和資料區</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">長度不定,配置設定耗時</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">應用程式和協定棧</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p><span style="font-family:Calibri"><span style="font-size:18px">PBUF_POOL</span></span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">記憶體池,包括<span style="font-family:Calibri">pbuf</span>和資料區</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">長度固定,配置設定快</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">中斷服務程式</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p><span style="font-family:Calibri"><span style="font-size:18px">PBUF_ROM</span></span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">記憶體池,僅包括<span style="font-family:Calibri">pbuf</span></span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">所指資料位于<span style="font-family:Calibri">ROM</span>中</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">應用程式引用記憶體區</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p><span style="font-family:Calibri"><span style="font-size:18px">PBUF_REF</span></span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">記憶體池,僅包括<span style="font-family:Calibri">pbuf</span></span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">所指資料位于<span style="font-family:Calibri">RAM</span>中</span></p>
</td>
<td valign="top">
<p><span style="font-size:18px">應用程式引用記憶體區</span></p>
</td>
</tr>
</tbody>
</table>
<p align="center"><span style="font-size:18px">表<span style="font-family:Calibri">1 pbuf</span>類型與特點</span></p>
<p><span style="font-size:18px">每一種<span style="font-family:Calibri">pbuf</span>配置設定記憶體的方式都不一樣,如圖<span style="font-family:Calibri">2</span>所示。</span></p>
<p></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517103957062" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">2</span>四種資料包管理結構</span></p>
<p><span style="font-size:18px">隻有選擇合适的<span style="font-family:Calibri">pbuf</span>類型才能發揮<span style="font-family:Calibri">LWIP</span>的最大性能,一個資料包可能是多種<span style="font-family:Calibri">pbuf</span>的組合,用連結清單連接配接起來,如圖<span style="font-family:Calibri">3</span>所示。</span></p>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104017062" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">3 pbuf</span>連結清單</span></p>
<h3><a name="t3"></a><span style="font-size:18px"><span style="font-family:Calibri">2.</span> 設定記憶體大小</span></h3>
<p><span style="font-size:18px">為<span style="font-family:Calibri">LWIP</span>開辟一個專用的記憶體堆是應該的,這樣一來<span style="font-family:Calibri">LWIP</span>的<span style="font-family:Calibri">mem_alloc()</span>和<span style="font-family:Calibri">mem_free()</span>都将基于該堆記憶體進行配置設定和回收,不影響其他系統記憶體的使用。如圖<span style="font-family:Calibri">1</span>左所示,<span style="font-family:Calibri">lwipopt.h</span>檔案中宏<span style="font-family:Calibri">MEM_SIZE</span>定義了堆區的大小,對于一個負荷較重的系統堆區需要配置設定較大。</span></p>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104035671" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">4</span>堆和<span style="font-family:Calibri">PBUF_ROM</span>記憶體區</span></p>
<p align="left"><span style="font-size:18px"><span style="font-family:Calibri">LWIP</span>使用<span style="font-family:Calibri">PBUF_ROM</span>類型的記憶體池來發送“隻讀”資料(處于<span style="font-family:Calibri">ROM</span>中或者其他程序中不可修改),宏<span style="font-family:Calibri">MEMP_NUM_PBUF</span>定義了該緩沖池的個數,如圖<span style="font-family:Calibri">2</span>右所示。</span></p>
<p align="left"><span style="font-size:18px">在<span style="font-family:Calibri">ISR</span>(中斷服務程式中)經常需要快速配置設定一部分記憶體進行資料存儲,這是通過<span style="font-family:Calibri">PBUF_POOL</span>類型的緩沖區實作的。為此需要定義兩個宏:<span style="font-family:Calibri">PBUF_POOL_SIZE</span>定義緩沖池的個數,<span style="font-family:Calibri">PBUF_POOL_BUFSIZE</span>定義單個緩沖區的大小,如圖<span style="font-family:Calibri">5</span>所示。</span></p>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104109093" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖5 <span style="font-family:Calibri">
PBUF_POOL</span>記憶體區</span></p>
<h3><a name="t4"></a><span style="font-size:18px"><span style="font-family:Calibri">3 </span>宏編譯開關</span></h3>
<p><span style="font-size:18px">若定義<span style="font-family:Calibri">MEM_LIBC_MALLOC=1</span>,直接使用<span style="font-family:Calibri">C</span>庫中的<span style="font-family:Calibri">malloc</span>、free來配置設定動态記憶體;否則使用LWIP自帶的mem_malloc、mem_free等函數。</span></p>
<p><span style="font-size:18px">若定義MEMP_MEM_MALLOC=1,則memp.c中的全部内容不會被編譯,用記憶體堆來實作記憶體池配置設定,使用這種方式得考慮是否能忍受記憶體堆配置設定帶來的時間延遲。</span></p>
<p><span style="font-size:18px">若定義MEM_USE_POOLS=1,則mem.c中的全部内容不會被編譯,用記憶體池來實作記憶體堆的配置設定,使用這種方式得考慮是否能忍受因為POOL記憶體固定大小而帶來的記憶體浪費。此外使用者需要定義宏MEM_USE_CUSTOM_POOLS=1,還需要額外實作一個頭檔案lwippools.h,并在其中開辟一些用于記憶體堆配置設定函數的記憶體池POOL,開辟空間的格式如下:</span></p>
<p><span style="font-size:18px">LWIP_MALLOC_MEMPOOL_START</span></p>
<p><span style="font-size:18px">LWIP_MALLOC_MEMPOOL(20, 256)</span></p>
<p><span style="font-size:18px">LWIP_MALLOC_MEMPOOL(10, 512)</span></p>
<p><span style="font-size:18px">LWIP_MALLOC_MEMPOOL_END</span></p>
<h2><a name="t5"></a><span style="font-size:18px">二<span style="font-family:Cambria"> LWIP</span>啟動時序</span></h2>
<p><span style="font-size:18px">圖<span style="font-family:Calibri">6</span>展示了<span style="font-family:Calibri">LWIP</span>啟動時序,大部分函數都是<span style="font-family:Calibri">LWIP</span>自帶的,主要的移植代碼是<span style="font-family:Calibri">eth_init()</span>實作初始化以太網接口,啟動程式會建立<span style="font-family:Calibri">2</span>個線程:<span style="font-family:Calibri">tcpip_thread</span>負責<span style="font-family:Calibri">LWIP</span>的絕大部分工作(主要是協定棧的解析和系統運作),<span style="font-family:Calibri">ethernetif_thread</span>負責從網口接收資料包再傳遞給<span style="font-family:Calibri">tcpip_thread</span>線程進行處理。</span></p>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104136359" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖6<span style="font-family:Calibri"> LWIP</span>啟動函數</span></p>
<h2><a name="t6"></a><span style="font-size:18px">三<span style="font-family:Cambria"> LWIP</span>運作邏輯</span></h2>
<h3><a name="t7"></a><span style="font-size:18px"><span style="font-family:Calibri">1 </span>接收資料包</span></h3>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104209218" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖7<span style="font-family:Calibri"></span>接收資料包</span></p>
<p align="left"><span style="font-size:18px">當以太網口接收到一個資料包後,<span style="font-family:Calibri">EMAC_IRQ</span>中斷服務程式通過信号量通知<span style="font-family:Calibri">ethernetif</span>線程,<span style="font-family:Calibri">ethernetif</span>線程調用<span style="font-family:Calibri">low_level_input()</span>接收該資料包并通過郵箱傳遞給<span style="font-family:Calibri">tcpip_thread</span>線程,<span style="font-family:Calibri">tcpip_thread</span>根據該資料包的類型進行相應處理。它是建立在消息傳遞的基礎上的,如圖<span style="font-family:Calibri">8</span>所示。</span></p>
<p align="left"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104224468" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖8<span style="font-family:Calibri"></span>資料包消息的産生和處理</span></p>
<h3><a name="t8"></a><span style="font-size:18px"><span style="font-family:Calibri">2 SequentialAPI</span>函數調用</span></h3>
<p><span style="font-size:18px"><span style="font-family:Calibri">API</span>設計的核心在于讓使用者程序負責盡可能多的工作,例如資料的計算、拷貝等;而協定棧程序隻負責簡單的通信工作,這是很合理的,因為系統可能存在多個應用程式,它們都使用協定棧程序提供的通信服務,保證核心程序的高效性和實時性是提高系統性能的重要保障。程序之間通信使用IPC技術,包括郵箱、信号量和共享記憶體,如圖9所示。</span></p>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104250140" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖9<span style="font-family:Calibri"></span>協定棧<span style="font-family:Calibri">API</span>實作</span></p>
<p><span style="font-size:18px">以函數<span style="font-family:Calibri">netconn_bind()</span>為例看<span style="font-family:Calibri">API</span>是如何實作的,首先使用者程式中調用函數<span style="font-family:Calibri">netconn_bind()</span>綁定一個連接配接,則這個函數實作時,是通過向核心程序發送一個<span style="font-family:Calibri">TCPIP_MSG_API</span>類型的消息,告訴核心程序執行<span style="font-family:Calibri">do_bind</span>函數:在消息發送後,函數阻塞在信号量上,等待核心處理該消息;核心在處理消息時,會根據消息内容調用<span style="font-family:Calibri">do_bind</span>,而<span style="font-family:Calibri">do_bind</span>會根據連接配接的類型調用核心函數<span style="font-family:Calibri">udp_bind</span>、tcp_bind或raw_bind;當do_bind執行完後,它會釋放信号量,這使被阻塞的netconn_bind得以繼續執行,整個過程如圖10所示。</span></p>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104311156" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖10<span style="font-family:Calibri"> API</span>函數實作</span></p>
<h2><a name="t9"></a><span style="font-size:18px">四<span style="font-family:Cambria"> TCP/IP</span>核心知識點</span></h2>
<h3><a name="t10"></a><span style="font-size:18px"><span style="font-family:Calibri">1.</span> 滑動視窗</span></h3>
<p></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104347703" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">11</span>滑動視窗</span></p>
<p align="left"><span style="font-size:18px">接收視窗相關的字段中,<span style="font-family:Calibri">rcv_nxt</span>是自己期望收到的下一個位元組編号,<span style="font-family:Calibri">rcv_wnd</span>表示接收視窗的大小,<span style="font-family:Calibri">rcv_ann_wnd</span>表示将向對方通告的視窗大小值,這個值在封包發送時會被填在首部中的視窗大小字段,<span style="font-family:Calibri">rcv_ann_right_edge</span>記錄了上一次視窗通告時視窗右邊界取值。上面這四個字段都會随着資料的發送和接收動态地改變,如圖<span style="font-family:Calibri">12</span>所示。</span></p>
<p align="left"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104453234" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖12<span style="font-family:Calibri"></span>接收視窗</span></p>
<p><span style="font-size:18px">發送視窗中,<span style="font-family:Calibri">lastack</span>記錄了被接收方确認的最高序列号,<span style="font-family:Calibri">snd_nxt</span>表示自己将要發送的下一個資料的起始編号,<span style="font-family:Calibri">snd_wnd</span>記錄了目前的發送視窗大小,它常被設定為接收方通告的接收視窗值,<span style="font-family:Calibri">snd_lbb</span>記錄了下一個被應用程式緩存的資料的起始編号,如圖<span style="font-family:Calibri">10</span>所示。</span></p>
<p><span style="font-size:18px">上面這四個字段的值也是動态變化的,每當收到接收方的一個有效<span style="font-family:Calibri">ACK</span>後,<span style="font-family:Calibri">lastack</span>的值就做相應的增加,指向下一個待确認資料的編号,當發送一個封包後,<span style="font-family:Calibri">snd_nxt</span>的值就做相應的增加,指向下一個待發送資料,<span style="font-family:Calibri">snd_nxt</span>和<span style="font-family:Calibri">lastack</span>之間的內插補點不能超過<span style="font-family:Calibri">snd_wnd</span>的大小。</span></p>
<p><span style="font-size:18px">由于實際資料發送時是按照封包段的形式組織的,是以可能存在這樣的情況:即使發送視窗允許,但并不是視窗内的所有資料都能發送以填滿視窗,如圖<span style="font-family:Calibri">13</span>中編号為<span style="font-family:Calibri">11</span>~<span style="font-family:Calibri">13</span>的資料,可能因為它們太小不能組織成一個有效的封包段,是以不會被發送。發送方會等到新的确認到來,進而使發送視窗向右滑動,使得更多的資料被包含在視窗中,這樣再啟動下一個封包段的發送。</span></p>
<p align="left"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517104411171" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">13</span>發送視窗</span></p>
<h3><a name="t11"></a><span style="font-size:18px"><span style="font-family:Calibri">2.</span> 三次握手</span></h3>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517110403718" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">14</span>連接配接建立過程</span></p>
<h3><a name="t12"></a><span style="font-size:18px"><span style="font-family:Calibri">3.</span> 斷開連接配接</span></h3>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517110515906" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">15</span>連接配接斷開過程</span></p>
<h3><a name="t13"></a><span style="font-size:18px"><span style="font-family:Calibri">4.</span> <span style="font-family:Calibri">TCP</span>狀态轉換</span></h3>
<p></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517110926515" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">16 TCP</span>狀态轉換圖</span></p>
<h3><a name="t14"></a><span style="font-size:18px"><span style="font-family:Calibri">5.</span> 同時打開</span></h3>
<p align="center"></p>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517110947250" alt=""></span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">17</span>雙方同時打開</span></p>
<h3><a name="t15"></a><span style="font-size:18px"><span style="font-family:Calibri">6.</span> 同時關閉</span></h3>
<p align="center"><span style="font-size:18px"><img src="https://img-blog.csdn.net/20140517114518140" alt=""></span></p>
<p align="center"><span style="font-size:18px"> </span></p>
<p align="center"><span style="font-size:18px">圖<span style="font-family:Calibri">18</span>雙方同時關閉</span></p>
<h2><a name="t16"></a><span style="font-size:18px">五正确使用<span style="font-family:Cambria">LWIP</span></span></h2>
<p><span style="font-size:18px">一般說來<span style="font-family:Calibri">LWIP</span>協定棧是比較穩定的,尤其像<span style="font-family:Calibri">V1.3.2</span>經曆過業界廣泛使用和工程應用,完全可以應用于<a href="http://lib.csdn.net/base/embeddeddevelopment" target="_blank" rel="external nofollow" class="replace_word" title="嵌入式開發知識庫" target="_blank" style="color:#df3434; font-weight:bold;">嵌入式</a>産品。那為什麼還是有很多人反映<span style="font-family:Calibri">LWIP</span>不穩定呢?主要是以下幾個方面的原因:</span></p>
<p><span style="font-size:18px"><span style="font-family:Calibri">1.</span> 網絡硬體驅動<span style="font-family:Calibri"> </span>確定<span style="font-family:Calibri">EMAC</span>口接收與發送穩定可靠</span></p>
<p><span style="font-size:18px"><span style="font-family:Calibri">2.</span> 移植<span style="font-family:Calibri">LWIP </span>基于<span style="font-family:Calibri">OS</span>的移植代碼正确穩定</span></p>
<p><span style="font-size:18px"><span style="font-family:Calibri">3.</span> 配置<span style="font-family:Calibri">LWIP </span>根據裝置<span style="font-family:Calibri">RAM</span>尺寸進行合理配置</span></p>
<p><span style="font-size:18px"><span style="font-family:Calibri">1)</span> 值<span style="font-family:Calibri">(PBUF_POOL_SIZE * PBUF_POOL_BUFSIZE)</span>必須大于<span style="font-family:Calibri">TCP_SND_BUF</span>和<span style="font-family:Calibri">TCP_WND</span>,否則容易引起錯誤;</span></p>
<p><span style="font-size:18px"><span style="font-family:Calibri">2)</span> 當記憶體有限時<span style="font-family:Calibri">TCP</span>發送不能太快(具體值依賴于配置設定記憶體的大小),否則引起<span style="font-family:Calibri">tcp_enqueue()</span>邏輯錯誤;</span></p>
<p><span style="font-size:18px"><span style="font-family:Calibri">4.</span> 調用<span style="font-family:Calibri">LWIP</span>的<span style="font-family:Calibri">API</span>函數<span style="font-family:Calibri"> </span>正确使用<span style="font-family:Calibri">API</span>函數,特别防止記憶體洩露。</span></p>
<p><span style="font-size:18px"><span style="font-family:Calibri">5.</span> 資源不足<span style="font-family:Calibri"> </span>打開報警提醒,當資源不夠時提醒設計者</span></p>
<h2><a name="t17"></a><span style="font-size:18px">六<span style="font-family:Cambria"> LWIP</span>常見問題</span></h2>
<h3><a name="t18"></a><span style="font-size:18px"><span style="font-family:Calibri">1.</span> 網卡驅動程式</span></h3>
<p><span style="font-size:18px">首先,必須将協定棧完全初始化才能打開網絡接收功能,接收中斷必須将資料封裝在<span style="font-family:Calibri">PBUF</span>中,然後交會給協定棧核心處理。其次,<span style="font-family:Calibri">LWIP</span>的全局變量(<span style="font-family:Calibri">arp_table,netif_list,udp_pcbs</span>等)確定賦初值<span style="font-family:Calibri">0</span>,否則容易一運作就崩潰。</span></p>
<h3><a name="t19"></a><span style="font-size:18px"><span style="font-family:Calibri">2.</span> 記憶體洩露</span></h3>
<p><span style="font-size:18px">第一個原則(責任制):誰配置設定記憶體,誰就負責回收。</span></p>
<p><span style="font-size:18px">第二個原則(對稱性):配置設定記憶體者與回收記憶體者一一對應構成閉環。</span></p>
<p><span style="font-size:18px">另外,需要特别注意一些系統函數的調用,它們也會帶來記憶體洩露,如:</span></p>
<p><span style="font-size:18px">例<span style="font-family:Calibri">1</span></span></p>
<p><span style="font-family:Calibri"><span style="font-size:18px">newconn = netconn_accept(conn);</span></span></p>
<p><span style="font-family:Calibri"><span style="font-size:18px">do_something_for(newconn);</span></span></p>
<p><span style="font-family:Calibri"><span style="font-size:18px">netconn_close(newconn);</span></span></p>
<p><span style="font-size:18px"><strong><em><span style="color:red"><span style="font-family:Calibri">netconn_delete(newconn); </span></span></span></span></em></span></p>
<p><span style="font-family:Calibri"><span style="font-size:18px"> </span></span></p>
<p><span style="font-size:18px">例<span style="font-family:Calibri">2</span></span></p>
<p><span style="font-family:Calibri"><span style="font-size:18px">inbuf = netconn_recv(conn);</span></span></p>
<p><span style="font-family:Calibri"><span style="font-size:18px">do_something_for(inbuf);</span></span></p>
<p><span style="font-size:18px"><strong><em><span style="color:red"><span style="font-family:Calibri">netbuf_delete(inbuf); </span></span></span></span></em></span></p>
<h3><a name="t20"></a><span style="font-size:18px"><span style="font-family:Calibri">3.</span> <span style="font-family:Calibri">PC</span>機無法與<span style="font-family:Calibri">LWIP</span>建立<span style="font-family:Calibri">TCP</span>連接配接</span></h3>
<p><span style="font-size:18px">問題:<span style="font-family:Calibri">PC</span>機能夠與<span style="font-family:Calibri">LWIP</span>裝置<span style="font-family:Calibri">PING</span>操作成功,但是無法建立<span style="font-family:Calibri">TCP</span>連接配接。</span></p>
<p><span style="font-size:18px">原因:通過代碼跟蹤,發現<span style="font-family:Calibri">LWIP</span>發出了<span style="font-family:Calibri">SYN+ACK</span>資料包,但是<span style="font-family:Calibri">PC</span>機無法接收該握手資料包,該資料包為<span style="font-family:Calibri">60</span>位元組,小于以太網的最小長度(<span style="font-family:Calibri">64</span>位元組),而<span style="font-family:Calibri">LWIP</span>裝置的<span style="font-family:Calibri">EMAC</span>沒有設定短小資料包填充功能,導緻<span style="font-family:Calibri">PC</span>機無法接收該短資料包。</span></p>
<p><span style="font-size:18px">解決:使能<span style="font-family:Calibri">EMAC</span>的短小資料包填充功能。</span></p>
<p><span style="font-size:18px; font-family:Calibri"> </span></p>
</div>