面向報文(UDP)和面向字節流(TCP)的區別
面向報文的傳輸方式是應用層交給UDP多長的報文,UDP就照樣發送,即一次發送一個報文。因此,應用程序必須選擇合適大小的報文。若報文太長,則IP層需要分片,降低效率。若太短,會是IP太小。UDP對應用層交下來的報文,既不合並,也不拆分,而是保留這些報文的邊界。這也就是說,應用層交給UDP多長的報文,UDP就照樣發送,即一次發送一個報文。
面向字節流的話,雖然應用程序和TCP的交互是一次一個數據塊(大小不等),但TCP把應用程序看成是一連串的無結構的字節流。TCP有一個緩沖,當應用程序傳送的數據塊太長,TCP就可以把它划分短一些再傳送。如果應用程序一次只發送一個字節,TCP也可以等待積累有足夠多的字節后再構成報文段發送出去。
下圖是TCP和UDP協議的一些應用。
下圖是TCP和UDP協議的比較。
這里再詳細說一下面向連接和面向無連接的區別:
面向連接舉例:兩個人之間通過電話進行通信;
面向無連接舉例:郵政服務,用戶把信函放在郵件中期待郵政處理流程來傳遞郵政包裹。顯然,不可達代表不可靠。
從程序實現的角度來看,可以用下圖來進行描述。
從上圖也能清晰的看出,TCP通信需要服務器端偵聽listen、接收客戶端連接請求accept,等待客戶端connect建立連接后才能進行數據包的收發(recv/send)工作。而UDP則服務器和客戶端的概念不明顯,服務器端即接收端需要綁定端口,等待客戶端的數據的到來。后續便可以進行數據的收發(recvfrom/sendto)工作。
在前面講解UDP時,提到了UDP保留了報文的邊界,下面我們來談談TCP和UDP中報文的邊界問題。在默認的阻塞模式下,TCP無邊界,UDP有邊界。
對於TCP協議,客戶端連續發送數據,只要服務端的這個函數的緩沖區足夠大,會一次性接收過來,即客戶端是分好幾次發過來,是有邊界的,而服務端卻一次性接收過來,所以證明是無邊界的;
而對於UDP協議,客戶端連續發送數據,即使服務端的這個函數的緩沖區足夠大,也只會一次一次的接收,發送多少次接收多少次,即客戶端分幾次發送過來,服務端就必須按幾次接收,從而證明,這種UDP的通訊模式是有邊界的。
TCP無邊界,造成對采用TCP協議發送的數據進行接收比較麻煩,在接收的時候易出現粘包,即發送方發送的若干包數據到接收方接收時粘成一包。由於TCP是流協議,對於一個socket的包,如發送 10AAAAABBBBB兩次,由於網絡原因第一次又分成兩次發送, 10AAAAAB和BBBB,如果接包的時候先讀取10(包長度)再讀入后續數據,當接收得快,發送的慢時,就會出現先接收了 10AAAAAB,會解釋錯誤 ,再接到BBBB10AAAAABBBBB,也解釋錯誤的情況。這就是TCP的粘包。
在網絡傳輸應用中,通常需要在網絡協議之上再自定義一個協議封裝一下,簡單做法就是在要發送的數據前面再加一個自定義的包頭,包頭中可以包含數據長度和其它一些信息,接收的時候先收包頭,再根據包頭中描述的數據長度來接收后面的數據。詳細做法是:先接收包頭,在包頭里指定包體長度來接收。設置包頭包尾的檢查位( 比如以0xAA開頭,0xCC結束來檢查一個包是否完整)。對於TCP來說:
1)不存在丟包,錯包,所以不會出現數據出錯 ;
2)如果包頭檢測錯誤,即為非法或者請求,直接重置即可。
為了避免粘包現象,可采取以下幾種措施。
一、對於發送方引起的粘包現象,用戶可通過編程設置來避免,TCP提供了強制數據立即傳送的操作指令push,TCP軟件收到該操作指令后,就立即將本段數據發送出去,而不必等待發送緩沖區滿;
二、對於接收方引起的粘包,則可通過優化程序設計、精簡接收進程工作量、提高接收進程優先級等措施,使其及時接收數據,從而盡量避免出現粘包現象;
三、由接收方控制,將一包數據按結構字段,人為控制分多次接收,然后合並,通過這種手段來避免粘包。
原文鏈接:https://blog.csdn.net/ce123_zhouwei/java/article/details/8976006