一、介紹
在程序的開發中,網絡開發是一個重要的應用場景。畢竟這些年IT行業之所以火,主要還是互聯網(移動互聯網)帶來的。網絡開發,有各種平臺、框架以及系統和庫提供的API,如果說網絡開發是一個特別復雜和困難的場景(前提了高并發等以上的場景),估計做過這類項目和有過接觸的開發人員都會贊同。
本文不介紹網絡開發中的各種異常、問題以及一些開發經驗,只從設計的角度分析一下,網絡開發人員經常提到的網絡數據包(指TCP/IP)的粘包和分包的情況。
二、粘包和分包
從TCP/IP的設計角度看,做為一種數據流的傳輸,根本就沒有什么 粘包和分包的問題。所謂粘包和分包其實是面向應用層的一種說法,而UDP的開發中由于協議本身設計和消息傳輸的特性不存在這類問題。給大家舉一個例子,大家都有過快遞收發的經驗,大家會認為自己發送一個小快遞(比如一件衣服),快遞公司會專門安排一輛車給你送到客戶手中么?反過來來也一樣,要發送一個非常多的成套的產品,快遞公司也不會因為這個去購買一個更大的車去運送而是會根據情況將其拆開用多輛車來發送。明白了這個,就明白了網絡包為什么會有粘包和分包了。
TCP/IP發送為了兼顧效率和性能,在處理一些小數據包比如IM通信中的互相打招呼發個字母時,就會合并其它的一些數據再發送;而如果雙方發送一些大數據時(不考慮單獨傳輸),又會拆開為多個包進行發送。而不同的平臺和系統可能網絡的緩沖區也有所不同,那么接收到的數據就可能需要進行拆分,恢復成小的包或等待數據最終形成一個完整的包。
這個在前面分析Nagle算法時,給大家分析過。
三、如何處理
那么在設計上如何應對這種情況呢?
首先,在數據傳輸的格式上,就要考慮IP包的大小,與其盡量適配(比如固定大小)。不要設計出過大或過小的包,但這樣做也有其缺點,比如不靈活,小包浪費帶寬等等。
其次,對網絡的原始通信配置進行修改,比如禁止諸如Nagle算法的應用,但這樣做的缺點是可能導致一些性能上的損失。
最后,設計一些規則,允許網絡通信中對粘包和分包不敏感,比如自描述的數據,網絡只需將數據保存成功即可,不考慮數據包的內容。同樣,這樣做的缺點一個是場景應用有限,另外引入了額外的復雜性。
不過話說回來,網絡的應用千差萬別,光從設計上是無法完全處理粘包和分包的,只能說是盡量完善。最終對其的處理,仍然需要開發者自行進行相關的數據處理。或者可以這樣理解,解決粘包這類問題,是要進行整體上的考慮的,在設計上、協議棧上和緩沖區以及應用層的處理上等等進行一個全面的處理和解決。
四、總結
這里只是從設計角度對粘包和分包進行了處理,而諸如常見的在開發的層次進行處理如增加分隔符、自定義格式(消息頭/消息體)等等這些都沒有討論。之所以這樣,目的就是讓大家明白設計在抽象層面的作用與實際開發層面的作用的不同。
很多東西不是簡單的一刀就能切開,往往是你中有我,我中有你。但在設計得的心中,得有設計這個抽象的想法一直存在!