1. 程式人生 > >概說《TCP/IP詳解 卷2》第10章 IP的分片和重灌

概說《TCP/IP詳解 卷2》第10章 IP的分片和重灌

本文要點

  • 引言

  • 分片

  • ip_optcopy函式

  • 重灌

  • ip_reass函式

  • ip_slowtimo函式

  • 小結

引言

    IP具有一種重要功能,就是當分組過大而不適合在所選硬體介面上傳送時,能夠對分組進行分片。過大的分組被分成兩個或者多個大小合適的在所選定網路上傳送的IP分片。而在去目的主機的路途中,分片還可能被中間的路由器繼續分片。因此,在目的主機上,一個IP資料報可能放在一個IP分組內,或者如果被分片,就放在多個IP分組內。因為各個分片可能以不同的路徑到達目的主機,所有隻有目的主機才能看到所有分片。因此,也只有目的主機才能把所有分片重灌成一個完整的資料報,提交給相應的運輸層協議。

    IP首部內有三個欄位實現分片和重灌:標識欄位(ip_id)、標誌欄位(ip_off的3個高位位元)和偏移欄位(ip_off的13個低位位元)。標誌欄位由三個1bit標誌組成。位元0是保留的,必須為0;位元1是“不分片”標誌;位元2是“更多分片”標誌。在Net/3中,標誌和偏移欄位結合起來,由ip_off訪問,如圖1所示。

圖1 ip_off控制IP分組的分片

    Net/3通過使用IP_DF和IP_MF掩去ip_off來訪問DF和MF。ip_off的其它13bit指出在原始資料報內分片的位置,以8位元組為單元計算。因而,除最後一個分片外,其它每個分片都希望是一個8位元組倍數的資料,從而使後面的分片從8位元組邊界開始。圖2顯示了在原始資料報內的位元組偏移關係,以及在分片的IP首部內分片的偏移(ip_off的低位13bit)。

    圖2顯示了把一個最大的IP資料報分成8190個分片,除最後一個分片包含3個位元組外,其它每個分片都包含8個位元組;而且除最後一個分片外,其餘分片都設定了MF位元。

圖2 65535位元組的資料報分片

    原始資料報上面的數字是該資料部分在資料報內的位元組偏移。分片偏移(ip_off)是從資料報的資料部分開始計算的。分片不可能含有偏移超過65514的位元組,因為如果這樣的話,重灌的資料報會大於65535位元組,這是ip_len欄位的最大值。這就限制了ip_off的最大值為8189(8189x8=65512),只為最後一個分片留下3位元組空間。如果有IP選項,則偏移還要小些。

    因為IP網際網路是無連線的,所以,在目的主機上,來自一個數據報的分片必然會與來自其它資料報的分片交錯。ip_id是唯一地標識某個特定資料報的分片。源系統用相同的源地址(ip_src)、目的地址(ip_dst)和協議(ip_p)值,作為資料報在網際網路上生命期的值,把每個資料報的ip_id設定成一個唯一的值。

    總而言之,ip_id標識了特定資料報的分片,ip_off確定了分片在原始資料報內的位置,除最後一個分片外,MF標識每個分片。

分片

    我們現在回到ip_output,分析分片程式碼。在概說《TCP/IP詳解 卷2》第8章 IP:網際協議圖20中,如果分組的大小不超過選定出介面的MTU,就在一個鏈路級幀中傳送它。否則,必須對分組分片,並在多個幀中將其傳送。分組可以是一個完整的資料報或者它自己也是前面系統建立的分片。我們分三個部分討論分片程式碼:

  • 確定分片大小(圖3)

  • 構造分片(圖4)

  • 構造第一個分片併發送分片(圖5)

圖3 函式ip_output:確定分片大小

253~261 分片演算法很簡單,但由於對mbuf結構鏈的操作使實現很複雜。如果DF位元禁止分片,則ip_output丟棄該分組,並返回EMSGSIZE。如果資料報是在本地生成的,則運輸協議把錯誤傳回該程序;如果分組是被轉發的,則ip_forward生成一個ICMP目的地不可達差錯報文,並指出不分片就無法轉發該分組。

262~266 每個分片中的資料位元組數len的計算是用介面的MTU減去分組首部的長度後,捨去低位的3個位元(&~7),成為8位元組倍數。如果MTU太小,使每個分片中無法含有8位元組的資料,則ip_output返回EMSGSIZE。

    每個新的分片中都包含:一個IP首部、某些原始分組中的選項以及最多len長度的資料。

    圖4中的程式碼,以一個C的複合語句開始,構造從第2個分片開始的分片表。在分片表生成後(圖5),原來的分組被轉換成第一個分片。

圖4 函式ip_output:構造分片

圖5 函式ip_output:傳送分片

267~269 外部塊允許在函式中離使用點更近一點的地方定義mhlen、firstlen和mnext。這些變數的範圍一直到塊的末尾,它們隱藏其它在塊外定義的有相同名字的變數。

270~276 因為原來的快取鏈現在成了第一個分片,所以for迴圈從第2個分片的依稀開始:hlen+len。對於每個分片,ip_output採取以下動作:

  • 277~284 分配一個新的分組快取,調整m_data指標,為一個16位元組鏈路層首部(max_linkhdr)騰出空間。如果ip_output不這麼做,則網路介面驅動器就必須再分配一個mbuf來儲存鏈路層首部或者移動資料。兩種工作都耗時,在這裡容易處理從而避免問題。

  • 285~290 從原來的分組中把IP首部和IP選項複製到新的分組中。前者複製在一個結構中;ip_optcopy只複製那些將被複制到每個分片中的選項。

  • 291~297 設定分片包括MF位元的偏移欄位(ip_off)。如果原來分組中已設定MF位元,則把所有分片中都把MF置位;如果原來分組中沒有設定MF位元,則除了最後一個分片外,其它所有分片中的MF都置位。

  • 298 為分片設定長度,解決首部小一些(ip_optcopy可能沒有複製所有選項),以及最後一個分片的資料區小一些的問題。以網路位元組序列儲存長度。

  • 299~305 從原始分組中把資料複製到該分片中。如果必要,m_copy會再分配一個mbuf。如果m_copy失敗,則發出ENOBUFS。sendorfree丟棄所有已分配的快取。

  • 306~314 調整新建立的分片的mbuf分組首部,使其具有正確的全長。把新分片的介面指標清零,把ip_off轉換成網路位元組序列,計算新分片的檢驗和。通過m_nextpkt把該分片與前面的分片連結起來。

    在圖5中,ip_output構造了第一個分片,並把每個分片傳遞到介面層。

315~325 把末尾多餘的資料截斷後,原來的分組就轉換成第一個分片,同時設定MF位元,把ip_len和ip_off轉換成網路位元組序列,計算新的檢驗和。在這個分片中,保留所有的IP選項。在目的主機重灌時,只保留資料中的第一個分片的IP選項(圖25)。某些選項,如源路由選項,必須被複制到每個分片中,即使在重灌時都被丟棄了。

326~338 此時,ip_output可能有一個完整的分片表,或者已經產生了錯誤,都必須把生成的那部分的分片表丟棄。for迴圈遍歷該表,傳送分片或者由於error而丟棄該分片。

ip_optcopy函式

    在分片過程中,ip_optcopy(圖6)複製到達分組(如果分組是被轉發的)或者原始資料報中(如果該資料報是本地生成的)中的選項到外出的分片中。

圖6 函式ip_optcopy

395~422 ip_optcopy的引數是:ip,一個指向原始分組的IP首部指標;jp,一個指向新生成的分片的IP首部的指標;ip_optcopy初始化cp和dp指向每個分組的第一個選項,並在處理每個選項時把cp和dp向前移動。for迴圈每次複製一個選項,當它遇到EOL選項或者檢查完所有選項時。NOP選項被複制,用來維持後續選項的對齊限制。

    如果IPOPT_COPIED指示的copied位元被置位,則ip_optcopy把選項複製到新片中。如果某個選項的長度太大,就被截斷;ip_dooptions應該已經發現這種錯誤了。

423~426 第2個for迴圈把選項表填充到4位元組的邊界。由於分組首部長度(ip_hlen)是以4位元組為單位計算的,所以需要這個操作。這也保證後面跟著的運輸層首部與4位元組邊界對齊。這樣會提高效能,因為在許多運輸層協議的設計中,如果運輸層首部從一個32bit邊界開始,那麼32bit首部將按照32bit邊界對齊。

    圖7顯示了ip_optcopy的執行。

圖7 在分片中並不複製所有選項

    在圖7中,我們看到ip_optcopy不復制時間戳選項(它的copied位元為0),但卻複製LSRR選項(它的copied位元為1)。為了把新選項與4位元組邊界對齊,ip_optcopy也增加了一個EOL選項。

重灌

    到目前為止,我們已經討論了資料報的分片,現在再回到ipintr討論重灌過程。ipintr將分片重灌成一個完整的資料報,然後整個交給運輸層處理。ipintr接收的分片被傳給ip_reass,由它嘗試把分片重灌成一個完整的資料報。圖8顯示了ipintr的程式碼。

圖8 函式ipintr:分片處理

271~279 我們知道ip_off包含DF位元、MF位元和分片偏移。如果MF位元或者分片偏移非零,則DF就被掩蓋掉了,分組就是一個必須被重灌的分片。如果兩者都為零,則分組就是一個完整的資料報。跳過重灌程式碼,執行圖8中最後的else語句,它從全部資料報長度中排除了首部長度。

280~286 m_pullup把位於外部簇上的資料移動到mbuf的資料區。在mtod巨集開始工作之前,m_pullup必須把IP首部從外部簇移到mbuf的資料區中去。

287~297 Net/3在一個全域性雙向連結串列ipq上記錄不完整的資料報。這個名字可能容易產生誤解,因為這個資料結構並不是一個佇列。也就是說,可能在表的任何地方插入和刪除,並不限制一定要在末尾。

    ipintr對錶進行線性搜尋,為當前分片找到合適的資料報。記住分片是由4元組{ip_id、ip_src、ip_dst和ip_p}唯一標識。ipq的每個入口是一個分片表,如果ipintr找到一個匹配,則fp指向匹配的表。

298~303 在found語句,ipintr為方便重灌,修改了分組:

  • 304 ipintr修改了ip_len,從中減去標準IP首部和任何選項長度。

  • 305~307 ipintr把MF標誌複製到ipf_mff的低位,把ip_top覆蓋掉(&=~1只清除低位)。注意,在ipf_mff成為一個有效成員之前,必須把ip指向一個ipasfrag結構(圖11)。此時,可以把ip_off作為一個16bit的偏移,而不是3個標誌位元和一個13bit偏移來訪問了。

  • 308 用8乘以if_off,把它從以8位元組為單元轉換成以1位元組為單元。ipf_mff和ip_off決定ipintr是否應該重灌。圖9描述了不同的情況以及相應的動作,其中fp指向的是系統以前為該資料報接收的分片表。許多工作是由ip_reass做的。

圖9 ipintr和ip_reass中的IP分片處理

309~322 如果ip_reass通過把當前分片與以前收到的分片組合在一起,能重灌成一個完整的資料報,它就返回指向該重灌好的資料報的指標。如果沒有重灌好,則ip_reass儲存該分片,ipintr跳到next去處理下一個分片。

323~324 當到達一個完整的資料報時,就選擇這個else分支,並按照前面的一樣修改ip_hlen。大部分執行流程會到達else分支,因為收到的資料報大多數不是分片。

    如果重灌處理產生一個完整的資料報,ipintr就把這個完成的資料報上傳給相應的運輸層協議:

    (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen)

ip_reass函式

    ipintr把一個要處理的分片和一個指標傳給ip_reass,其中指標指向是的ipq中匹配的重灌首部。ip_reass可能重灌成功並返回一個完整的資料報,可能把該分片連結到資料報的重灌連結串列上,等待其它分片到達後重裝。每個重灌連結串列的表頭是一個ipq結構,如圖10所求。

圖10 ipq結構

52~60 用來標識一個數據報分片的四個欄位,ip_id、ip_src、ip_dst和ip_p,被儲存在每個重灌連結串列靜養的ipq結構中。Net/3用next和prev構造資料報連結串列,用ipq_next和ipq_pre構造分片的連結串列。

    到達分組的IP首部在被放在重灌連結串列之前,首先被轉換成一個ipasfrag結構,如圖11所示。

 圖11 ipasfrag結構

66~86 ip_reass在一個由ipf_next和ipf_prev連結起來的雙向迴圈連結串列上,收集某個資料報的分片。這些指標覆蓋了IP首部的源地址和目的地址。ipf_mff成員覆蓋ip結構中的ip_tos。其它成員是相同的。

    圖12顯示了分片首部連結串列(ipq)和分片(ipasfrag)之間的關係。

圖12 分片首部連結串列ipq和分片

    圖12的左下部是重灌首部的連結串列。表中第一個節點是全域性ipq結構,ipq。它永遠不會有自己的相關分片表。ipq表是一個雙向連結串列,用於支援快速插入和刪除。next和prev指標指向前一個和後一個ipq結構。

    圖12仍然沒有顯示重灌結構的所有複雜性。重灌程式碼很難跟蹤,因為它完全依靠指標指向底層mbuf上的三個不同的結構。

    圖13顯示了mubf、ipq結構、ipasfrag結構和ip結構之間的關係,包含了大量資訊:

  • 所有結構都放在一個mbuf的資料區內。

  • ipq連結串列由next和prev連結起來的ipq結構組成。每個ipq結構儲存了唯一標識一個IP資料報的四個欄位(圖13中陰影部分)。

  • 當作為分片連結串列的頭訪問時,每個ipq結構被看成一個ipasfrag結構。這些分片由ipf_next和ipf_prev連結起來,分別覆蓋了ipq結構的ipq_next和ipq_prev成員。

  • 每個ipasfrag結構都覆蓋了到達分片的ip結構,與分片一起到達的資料在快取中跟在該結構之後。ipasfrag結構的陰影部分是成員和含義與其在ip結構中不太相同。

圖13 可通過多種結構訪問的一段記憶體區

    圖12顯示了這些重灌結構之間的物理連線,圖13顯示了ip_reass使用的覆蓋技術。圖14從邏輯的觀點說明重灌結構:該圖顯示了三個資料報的重灌,以及ipq連結串列和ipasfrag結構之間的關係。

圖14 三個IP資料報的重灌

    每個重灌連結串列的表頭包含原始資料報的識別符號、協議、源和目的地址。圖14中只顯示了ip_id欄位。分片表通過偏移欄位排序,如果MF位元被置位,則用MF標誌分片,缺少的分片出現在陰影裡。每個分片的數字顯示了該分片的開始和結束位元組相對於原始資料報資料區的相對偏移,而不是相對於原始資料報的IP首部。

    這個例子用來說明三個沒有IP選項的UDP資料報,其中每個資料報都有1024位元組的資料。每個資料報的全長是1052(20+8+1024)位元組,正好適合1500位元組的乙太網MTU。在到目的主機的途中,這些資料報會遇到一個SLIP鏈路,該鏈路上的路由器對資料報分片,使其大小適於放在典型的296位元組的SLIP MTU中。每個資料報分4個分片到達。第1個分片中包含一個標準的20位元組IP首部,8位元組UDP首部和264位元組資料。第2個和第3個分片中包含一個20位元組的IP首部和272位元組的資料。最後一個分片中在一個20位元組首部和216位元組資料(1032=272x3+216)。

    在圖14中,資料報5缺少一個包含272~543位元組的分片。資料報6缺少第一個分片0~271位元組,以及最後一個從偏移816開始的分片。資料報7缺少前三個分片0~815。

    圖15列出了ip_reass。前面講到,當目的地是本機的某個IP分片到達時,在處理完所有選項後,ipintr會呼叫ip_reass。

圖15 函式ip_reass:資料報重灌

343~358 當呼叫ip_reass時,ip指向分片,fp指向匹配的ipq結構或者為空。因為重灌只涉及每個分片的資料部分,所以ip_reass調整含有該分片的mbuf的m_data和m_len,減去每個分片的IP首部。

465~469 在重灌過程中,如果產生錯誤,該函式就跳到dropfrag。dropfrag增加ips_fragdropped,丟棄該分片,並返回一個空指標。

    在運輸層丟棄分片通常會嚴重降低效能,因為必須重傳整個資料報。TCP謹慎地避免分片,但是UDP應用程式必須採取步驟以避免對自己分片。

    所有IP實現必須能夠重灌最多576位元組的資料報。沒有通用的方法來確定遠端主機能重灌的最大資料報大小。我們將在27章看到TCP提供一個機制,可以確定遠端主機所能處理的最大資料報大小。UDP沒有這樣的機制,所以許多基於UDP的協議,都限制在576位元組左右。

    我們將分7個部分顯示重灌程式碼,從圖16開始。

圖16 函式ip_reass:建立重灌表

    a. 建立重灌表

359~366 當fp為空時,ip_reass用新的資料報的第一個分片建立一個重灌表。它分配一個mbuf來存放新表的頭(一個ipq結構),並呼叫insque,把該結構插入到重灌表的連結串列中。

    圖17列出了操作資料報和分片連結串列的函式。

圖17 ip_reass採用的佇列函式

    b. 重灌超時

367 ipq_ttl欄位用於限制等待分片以重灌成一個完整資料報的時間。這與IP首部的TTL欄位是不同的,IP首部的TTL欄位是為了限制分組在網際網路中最大的跳數。

    在Net/3中,重灌超時的初始值設為60(IPFRAGTTL)。因為每次核心呼叫ip_slowtimo時,ipq_ttl就減去1,而核心每500ms呼叫ip_slowtimo一次。那麼,如果系統在第一次接收到資料報的任一分片30秒後,還沒有組裝好一個完整的IP資料報,就丟棄該IP重灌連結串列。重灌定時器在連結串列被建立後的第一次呼叫ip_slowtimo時開始計時。

    重灌時間一般推薦為60~120秒,並且當收到資料報的第一個分片且定時器超時後,向源主機發出一個ICMP超時差錯報文。重灌後,總是丟棄其它分片的首部和選項,並且在ICMP差錯報文中必須包含出錯資料報的前64bit資料。所以,如果核心還沒收到分片0,它就不能發ICMP報文。

    c. 資料報識別符號

368~375 ip_reass在分配給該資料報的ipq結構中儲存ip_p、ip_id、ip_src和ip_dst,讓ipq_next和ipq_pre指標指向該ipq結構,讓q指向這個結構,並跳到insert(圖22),把第一個分片ip插入到新的重灌表中去。

    ip_reass的下一個部分(圖18),此時fp已不為空了,然後為新的分片找到正確的插入位置。

圖18 函式ip_reass:在重灌連結串列中找位置

376~381 因為fp不為空,所以for迴圈搜尋資料報的分片連結串列,找到一個偏移大於ip_off的分片。

    在目的主機上,分片包含的位元組範圍可能會相互覆蓋。發生這種情況的原因是,當一個運輸層協議重傳某個資料報時,採用與原來資料報不同的路由;而且,分片的模式也可能不同,這就導致在目的主機上的相互覆蓋;同時傳輸協議必須能強制IP使用原來的ID欄位,這樣才能使分片到達目的主機原先已存在(相同四元組)的重灌列隊中,才能識別該資料報可能是重傳的。

    Net/3並不為運輸層協議提供機制保證在重傳的資料報中重用IP ID欄位。在準備新資料時,在概說《TCP/IP詳解 卷2》第8章 IP:網際協議圖17中,ip_output通過增加全域性整數ip_id來賦一個新值,儘管如此,Net/3系統也能從讓運輸層用相同IP欄位重傳的IP資料報的系統上接收重疊分片。

    圖19說明分片可能以不同的方式與已到達的分片重疊。分片是按照它們到達目的主機的順序編號的。重灌的分片在圖19底部顯示,分片的陰影部分是被丟棄的多餘位元組。

圖19 可能會在目的主機重疊的分片的位元組範圍

    圖20中程式碼截斷或者丟棄到達的分片。

圖20 函式ip_reass:截斷到達分組

382~396 ip_reass把新片中與早到分片末尾重疊的位元組丟棄,截斷重複的部分(圖20中分片5的前部),或者如果新分片的所有位元組已經在早先的分片中(分片4)出現,就丟棄整個新分片(分片6)。

    圖21中的程式碼截斷或者丟棄已有的分片。

圖21 函式ip_reass:截斷已有分組

397~412 如果當前分片部分地與早到分片的前端部分重疊,就把早到分片中重複的資料截掉(圖19中分片2的前部)。丟棄所有與當前分片完全重疊的早到分片(分片3)。

    圖22中,到達分片被插入到重灌連結串列。

圖22 函式ip_reass:插入分組

413~426 在截斷後,ip_enq把該分片插入連結串列,並掃描連結串列,確定是否所有分片全部到達。如果還缺少分片,或者連結串列最後一個分片的ipf_mff被置位,ip_reass就返回0,並等待更多的分片。

    當目前的分片完成一個數據報後,整個連結串列被圖23所示的程式碼轉換成一個mbuf鏈。

圖23 函式ip_reass:重灌資料報

427~440 如果某個資料報的所有分片都被接收下來,while迴圈用m_cat把分片重新構造成資料報。

    圖24顯示了一個有三個分片的資料報的mbuf和ipq結構之間的關係。

圖24 m_cat重灌快取內的分片

    圖24中最暗的區域是分組的資料部分,稍淡的陰影部分是mbuf中未用的部分。有三個分片,每個分片都被存放在一個含有兩個mbuf的鏈上:一個分組首部和一個簇。每個分片的第一個快取上的m_data指標指向分組資料,而不是分組的首部。因此,由m_cat構造的快取只包含分片的資料部分。

    當一個分片含有多於208位元組時,情況通常是這樣。快取的“frag”部分是分片的IP首部。由於圖15中程式碼中m_data指標後移了hlen,所以各快取鏈第一個快取的m_data指標指向“opt”之後。

    圖25顯示了用所有分片的快取重灌的資料報。注意,分片2和3的IP部分和選項不在重灌的資料報裡。

圖25 重灌的資料報

    第一個分片的首部仍然被用作ipasfrag結構。它被圖26中的程式碼恢復成一個有效的IP資料報首部。

圖26 函式ip_reass:資料報重灌

    d. 重建資料報首部

441~456 ip_reass把ip指向連結串列的第一個分片,將ipasfrag結構恢復成ip結構:把資料報長度恢復成ip_len,源站地址恢復成ip_src,目的地址恢復成ip_dst;並把ipf_mff的低位清零。

    ip_reass用remque所整個分組從重灌連結串列中移走,丟棄連結串列表頭ipq結構,調整第一個快取中的m_len和m_data,把前端被隱藏起來的第一個分片的首部和選項包含進來。

    e. 計算分組長度

457~464 此處的程式碼總是被執行,因為資料報的第一個快取總是一個分組首部。for迴圈計算快取鏈中的資料的位元組數,並把值儲存在m_pkthdr.len中。

    在選項型別欄位中,copied位元的意義現在應該很明白了。因為目的主機只保留那些出現在第一個分片的中的選項,而且只有那些在分組去往目的主機的途中控制分組處理的選項才被複制下來。不復制那些在傳送過程中收集資訊的選項,因為當分組在目的主機上重灌時,所有收集的資訊都被丟棄了。

ip_slowtimo函式

    Net/3的各項協議可能指定每500ms呼叫一個函式。對IP而言,這個函式是ip_slowtimo,如圖27所示,為重灌連結串列上的分片計時。

圖27 函式ip_slowtimo

515~534 ip_slowtimo遍歷部分資料報的連結串列,減少重灌TTL欄位。當該欄位減為0時,就呼叫ip_freef,把與該資料報相關的分片都丟棄。在splnet外執行ip_slowtimo,避免到達分組修改連結串列。

    ip_freef顯示如圖28所示。

圖28 函式ip_freef

474~486 ip_freef移走並釋放連結串列上的fp指向的各分片,然後釋放連結串列本身。

    在第7章中,我們講到IP把ip_drain定義成一個當核心需要更多記憶體時才呼叫的函式。這種情況通常發生在分配快取時記憶體不夠時。ip_drain顯示如圖29所示。

圖29 函式ip_drain

538~545 IP釋放記憶體的最簡單辦法就是丟棄重灌連結串列上的所有IP分片。對屬於某個TCP報文段的分片,TCP最終會重傳該資料。屬於UDP資料報的IP分片就丟失了,基於UDP的協議必須在應用程式層處理這種情況。

小結

    本文介紹了當一個外出資料報過大而不適合在選定的網路上傳送時,ip_output如何對資料報分片。由於分片在向目的地傳送的途中可能繼續被分片,也有可能走不同的路徑,所以只有目的主機才能組裝原來的資料報。

    ip_reass接收到達的分片,並試圖重灌資料報。如果重灌成功則傳回ipintr,然後提交給相應的運輸層。所有IP實現必須能夠重灌最多576位元組的資料報。如果在一段合理時間內,分片未能重灌成一個完整的資料報,ip_slowtimo就丟棄不完整的資料報。

更多最新文章盡在公眾號:大白愛爬山,歡迎關注!