完美解決Python套接字編程時TCP斷包與粘包問題

首先,來看一個代碼,使用TCP協議,發送端發送一句話,接收端接收並顯示,運行完全正常。

 

接下來,把客戶端代碼稍微修改一下,連續發送多個數據,

 

按照正常的想法,在服務端輸出的信息應該是分爲多行的,這樣才和客戶端對應。然後運行結果並不是想象的那樣子。從運行結果來看,應該是服務端把收到的數據放在緩衝區裏了,有了足夠多的數據之後才處理。

recv()方法的參數用來確定一次從緩衝區中最多讀取多少字節的數據,爲了清楚其含義,稍微修改代碼,

 

學過計算機網絡的朋友一般會聽說過Nagle算法。在使用TCP協議進行傳輸時,會在有效數據前面增加大量頭部信息來保證可靠傳輸,如果發送的有效數據非常短,增加頭部帶來的額外開銷就非常大。爲了優化和減少帶寬佔用,避免大量小包堵塞網絡,發送端會在發送大量小包時積累一定數量的數據之後組成一個大包晚些時間再發送(粘包),在發送大包時會根據情況切分成多個包發送(斷包)。同理,接收端在接收大包時有可能會進行截斷以免緩衝區放不下(斷包),接收連續多個小包時會在緩衝區暫存一段時間合併成大包再處理(粘包),也就是所謂Nagle算法。

Nagle算法的優化在大部分情況下都是非常好的,但也會給接收端帶來一定的麻煩,必須要正確識別和讀取一個完整的包之後再處理,以免後面的功能代碼無法正常工作。這需要額外寫更多代碼來正確讀取一個完整的包,例如發送端先告知接收端要發送的數據長度,或者雙方約定好數據的起始標記和結束標記。

如果到網上(甚至一些書上)搜索資料,會說禁用Nagle算法就可以了,也就是設置套接字屬性啓用TCP_NODELAY,非常簡單。既然如此,那就趕緊用起來吧。

在Python中,標準庫socket封裝了套接字編程需要的功能,創建套接字之後可以使用setsockopt來設置當前套接字的各種屬性,其中就包括禁用斷包和粘包的延遲從而禁用Nagle算法。

 

結果顯示,這個選項根本沒有起作用。那會不會是需要在通信雙方都啓用TCP_NODELAY呢?於是把客戶端也設置一下,重新運行程序,發現還是沒有用。

繼續查資料,會有人說,要真正禁用Nagle算法只把TCP_NODELAY設置爲True是不夠的,還需要把接收端的接收緩衝區大小設置爲0纔行。原來是這樣啊,那就趕緊修改代碼吧,事實證明還是沒有用的。

 

也有資料顯示,通信雙方需要協商一下,爲避免接收端粘包時誤把下一條信息的一部分合併到當前信息尾部,可以協商一個起始標記和結束標記,接收端根據接收的信息來查找這些標記並進行正確的切分。這聽起來是個好思路,但真正用起來的時候難度還是很大的,感興趣的朋友可以嘗試一下。

再一個思路也是在傳輸大量數據時經常使用的,就是發送端首先告訴對方接下來要發送的數據長度,然後再發送實際數據。接收端首先接收一個整數來表示接下來要接收的數據總長度,然後使用循環來接收數據,直到恰好接收完剛纔約定的數據長度爲止。爲了避免發生粘包,接收端需要動態調整緩衝區大小來控制每次接收的數據,防止接收多了。

現在的問題就是如何確保把數據長度有效傳遞給對方了,可以使用Python標準庫struct把整數序列化爲字節串發送給對方,而這個字節串的長度固定爲4,這樣的話,接收端使用recv(4)接收到這個字節串再反序列化爲整數就可以了。

 

上面這個思路是完美的,也是優先推薦使用的,但是需要在編寫程序之前就確定好代碼思路和框架。

如果在編寫代碼時沒有遵循這個思路,都是直接進行發送和接收導致了粘包的發生,又不想對代碼進行大幅度的修改,可以考慮在發送完一段完整意義的數據之後加一個很小的延時,這樣接收端不會等待更多數據後一起處理。雖然這樣可以實現功能,但這個小延時的積累是非常大的,非常不適合服務端代碼的設計,要慎重使用。

 

在本文最後,給出一個多線程版本的Socket程序,供參考。

 

 

 

 

溫馨提示

關注本公衆號“Python小屋”,通過菜單“最新資源”==>“歷史文章”可以快速查看分專題的1000篇技術文章列表(可根據關鍵字在頁面上搜索感興趣的文章),通過“最新資源”==>“微課專區”可以免費觀看500節Python微課,通過“最新資源”==>“培訓動態”可以查看近期Python培訓安排,通過“最新資源”==>“教學資源”可以查看Python教學資源。

---董付國老師Python系列圖書---

友情提示:不建議購買太多,最好先通過京東、噹噹、天貓查閱圖書瞭解目錄和側重點,然後再選擇購買適合自己的書。

(1)《Python程序設計(第2版)》(ISBN:978-7-302-43651-5),清華大學出版社,2016年8月出版,2019年度清華大學出版社暢銷圖書

(2)《Python可以這樣學》(ISBN:978-7-302-45646-9),清華大學出版社,2017年2月

(3)《Python程序設計基礎(第2版)》(ISBN:978-7-302-49056-2)清華大學出版社,2018年1月出版,2019年度清華大學出版社暢銷圖書

(4)《中學生可以這樣學Python》(ISBN:978-7-302-48039-6)清華大學出版社

(5)《Python程序設計開發寶典》(ISBN:978-7-302-47210-0)清華大學出版社,2018年10月

(6)《玩轉Python輕鬆過二級》(ISBN:978-7-302-49916-9)清華大學出版社,2018年5月

(7)《Python程序設計基礎與應用》(ISBN:978-7-111-60617-8),機械工業出版社,2018年9月

(8)《Python程序設計實驗指導書》(ISBN:9787302525790),清華大學出版社,2019年4月

(9)《Python編程基礎與案例集錦(中學版)》(ISBN:978-7-121-35539-4),電子工業出版社,2019年4月

(10)《大數據的Python基礎》(ISBN:978-7-111-62455-4),機械工業出版社,預計2019年5月出版

(11)譯作《Python程序設計》,機械工業出版社(華章),2018年11月出版

(12)繁體版《Python也可以這樣學》,臺灣博碩文化股份有限公司,2017年10月出版,本書爲《Python可以這樣學》在臺灣發行的繁體版,兩本書內容一樣,不建議重複購買。

(13)《Python程序設計實例教程》(ISBN:978-7-111-63198-9),機械工業出版社

(14)《Python數據分析、挖掘與可視化》(ISBN:978-7-115-52361-7),人民郵電出版社,2019年12月

 

Python相關課程教材選用參考與建議

董付國老師Python在線課程資源使用方法

董付國老師6本Python教材PDF版免費閱讀

《Python數據分析、挖掘與可視化》前3章書稿PDF免費閱讀

《Python程序設計基礎與應用》前3章書稿PDF免費閱讀

號外號外--Python小屋刷題神器上線啦

《中學生可以這樣學Python》84節微課免費觀看地址

 

相關閱讀

Python實現多進程/多線程同時下載單個文件

Python 3.8實現支持斷點續傳的網絡文件下載功能

Python+winreg+netifaces查看網絡接口信息

Python自動接收微信羣消息並推送相應的公衆號文章

Python+psutil獲取本機所有聯網的應用程序信息

Python多線程編程的一個掉進去不太容易爬出來的坑

Python+socket+多線程實現同時應答多客戶端的自助聊天機器人

Python實現機房管理軟件的文件分發功能

技術要點|Python監控學生端電腦屏幕自動識別學習狀態

Python多線程與Socket編程綜合案例:素數

Python批量下載電子郵件附件並彙總合併Excel文件

Python監視電子郵箱並提示收到新郵件

Python版課堂管理系統中使用UDP廣播遠程關閉客戶端程序思路與源碼

使用Python實現電子郵件羣發功能

基於Python的電子教室軟件中遠程關機功能的原理與實現

Python獲取本機所有IP地址

Python實現局域網內屏幕廣播的技術要點分析

使用Python開發SQLite代理服務器

Python獲取局域網內所有機器IP地址與網卡MAC地址

Python獲取本機所有網卡的MAC地址

Python+flask+flask-email發送帶附件的電子郵件

Python使用UDP協議打造在線時間服務器

使用Python開發會聊天的智能小機器人

Python使用TCP協議編寫會聊天的小機器人

Python實現本機網絡流量監視器

Python使用UDP廣播實現服務器自動發現

Python網頁注入掛馬

Python監視域名對應IP地址變化情況

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章