TCP和UDP詳解


轉載用於收藏學習:原文鏈接

TCP和UDP詳解
計算機網絡知識掃盲:https://blog.csdn.net/hansionz/article/details/85224786
網絡編程套接字:https://blog.csdn.net/hansionz/article/details/85226345
HTTP協議詳解:https://blog.csdn.net/hansionz/article/details/86137260

前言

  本篇博客介紹TCP協議和UDP協議的各個知識點,這兩個協議都是位於傳輸層的協議,我們首先從傳輸層談起。

傳輸層

  傳輸層是TCP/IP協議五層模型中的第四層。它提供了應用程序間的通信,它負責數據能夠從發送端傳輸到接收端。其功能包括:一、格式化信息流;二、提供可靠傳輸。為實現后者,傳輸層協議規定接收端必須發回確認,並且假如分組丟失,必須重新發送。

再談端口號

  在網絡知識掃盲博客中談到端口號標識了一個主機上進行通信的不同應用程序。在TCP/IP協議中, 用"源IP", "源端口號", "目的IP", "目的端口號", "協議號" 這樣一個五元組來標識一個通信(可以通過 netstat -n查看,協議號指的是那個使用協議)。
一個進程可以綁定多個端口號,但是一個端口號不能被多個進程綁定。

 

端口號范圍划分

0 - 1023: 知名端口號,HTTP、FTP、 SSH等這些廣為使用的應用層協議他們的端口號都是固定的,自己寫的程序中,不能隨意綁定知名端口號。
1024 - 65535:操作系統動態分配的端口號。 客戶端程序的端口號,就是由操作系統從這個范圍分配的。
常見的知名端口號:

ssh服務器:22端口
ftp服務器:21端口
http服務器:80端口
telnet服務器:23端口
https服務器:443端口
MYSQL服務器:3306端口
在Linux操作系統中使用命令cat /etc/services可以看到所有的知名端口。

 

netstat工具: 用來查看網絡狀態

n 拒絕顯示別名,能顯示數字的全部轉化成數字
l 僅列出有在Listen (監聽)的服務狀態
p 顯示正在使用Socket的程序識別碼和程序名稱
t (tcp)僅顯示tcp相關選項
u u (udp)僅顯示udp相關選項
a (all)顯示所有選項,默認不顯示LISTEN相關
pidof [進程名]: 可以根據進程名直接查看服務器的進程id。例如:pidof sshd。

 

UDP協議,UDP協議報文格式

16位UDP長度表示整個數據報(UDP首部+UDP數據)的長度
如果校驗和出錯,就會直接丟棄(UDP校驗首部和數據部分)


UDP協議的特點:

無連接:只知道對端的IP和端口號就可以發送,不需要實現建立連接。
不可靠:沒有確認機制, 沒有重傳機制。如果因為網絡故障該段無法發到對方, UDP協議層也不會給應用層返回任何錯誤信息。
面向數據報: 應用層交給UDP多長的報文, UDP原樣發送既不會拆分,也不會合並。如果發送端調用一次sendto, 發送100個字節, 那么接收端也必須調用對應的一次recvfrom, 接收100個 字節,而不能循環調用10次recvfrom, 每次接收10個字節。所以UDP不能夠靈活的控制讀寫數據的次數和數量。


UDP的緩沖區UDP存在接收緩沖區,但不存在發送緩沖區

UDP沒有發送緩沖區,在調用sendto時會直接將數據交給內核,由內核將數據傳給網絡層協議進行后續的傳輸動作。為什么UDP不需要發送緩沖區? 因為UDP不保證可靠性,它沒有重傳機制,當報文丟失時,UDP不需要重新發送,而TCP不同,他必須具備發送緩沖區,當報文丟失時,TCP必須保證重新發送,用戶不會管,所以必須要具備發送緩沖區。

UDP具有接收緩沖區,但是這個接收緩沖區不能保證收到的UDP報文的順序和發送UDP報的順序一致,如果緩沖區滿了再到達的UDP數據報就會被丟棄。

UDP接收緩沖區和丟包問題:https://blog.csdn.net/ljh0302/article/details/49738191

UDP是一種全雙工通信協議。 UDP協議首部中有一個16位的大長度. 也就是說一個UDP能傳輸的報文長度是64K(包含UDP首部)。如果我們需要傳輸的數據超過64K, 就需要在應用層手動的分包, 多次發送, 並在接收端手動拼裝。

常見的基於UDP的應用層協議:

NFS:網絡文件系統
TFTP:簡單文件傳輸協議
DHCP:動態主機配置協議
BOOTP:啟動協議(用於無盤設備啟動)
DNS:域名解析協議
程序員在寫UDP程序時自己定義的協議

 


TCP協議
TCP全稱傳輸控制協議,必須對數據的傳輸進行控制。

TCP協議報文格式:

源端口號/目的端口號:表示數據從哪個進程來,要到那個進程去

32位序號:序號是可靠傳輸的關鍵因素。TCP將要傳輸的每個字節都進行了編號,序號是本報文段發送的數據組的第一個字節的編號,序號可以保證傳輸信息的有效性。比如:一個報文段的序號為300,此報文段數據部分共有100字節,則下一個報文段的序號為401。

32位確認序號:每一個ACK對應這一個確認號,它指明下一個期待收到的字節序號,表明該序號之前的所有數據已經正確無誤的收到。確認號只有當ACK標志為1時才有效。比如建立連接時,SYN報文的ACK標志位為0。

4位首部長度(數據偏移): 表示該TCP頭部有多少個32位bit(有多少個4字節),所以TCP頭部大長度是15 * 4 = 60。根據該部分可以將TCP報頭和有效載荷分離。TCP報文默認大小為20個字節。

6位標志位:

URG:它為了標志緊急指針是否有效。
ACK:標識確認號是否有效。
PSH:提示接收端應用程序立即將接收緩沖區的數據拿走。
RST:它是為了處理異常連接的, 告訴連接不一致的一方,我們的連接還沒有建立好, 要求對方重新建立連接。我們把攜帶RST標識的稱為復位報文段。
SYN: 請求建立連接; 我們把攜帶SYN標識的稱為同步報文段。
FIN:通知對方, 本端要關閉連接了, 我們稱攜帶FIN標識的為結束報文段。

16位的緊急指針:按序到達是TCP協議保證可靠性的一種機制,但是也存在一些報文想優先被處理,這時就可以設置緊急指針,指向該報文即可,同時將緊急指針有效位置位1。
16位窗口大小:如果發送方發送大量數據,接收方接收不過來,會導致大量數據丟失。然后接收方可以發送給發送發消息讓發送方發慢一點,這是流量控制。接收方將自己接收緩沖器剩余空間的大小告訴發送方叫做16位窗口大小。發送發可以根據窗口大小來適配發送的速度和大小,窗口大小最大是2的16次方,及64KB,但也可以根據選項中的某些位置擴展,最大擴展1G。
16位校驗和:發送端填充,CRC校驗。如果接收端校驗不通過, 則認為數據有問題(此處的檢驗和不光包含TCP首部也包含TCP數據部分)。

 


確認應答機制

接收端收到一條報文后,向發送端發送一條確認ACK,此ACK的作用就是告訴發送端:接收端已經成功的收到了消息,並且希望收到下一條報文的序列號是什么。這個確認號就是期望的下一個報文的序號。

每一個ACK都帶有對應的確認序列號,意思是告訴發送者,我們已經收到了哪些數據,下一個發送數據應該從哪里開始。 如上圖,主機A給主機B發送了1-1000的數據,ACK應答,攜帶了1001序列號。告訴主機A,我已經接受到了1-1000數據,下一次你從1001開始發送數據。

 

超時重傳:

TCP在傳輸數據過程中,還加入了超時重傳機制。假設主機A發送數據給主機B,主機B沒有收到數據包,主機B自然就不會應答,如果主機A在一個特定時間間隔內沒有收到主機B發來的確認應答,就會進行重發,這就是超時重傳機制。
當然還存在另一種可能就是主機A未收到B發來的確認應答,也可能是因為ACK丟失了。

因此主機B會收到很多重復數據,那么TCP協議需要能夠識別出那些包是重復的包, 並且把重復的包丟棄掉,這時候我們可以利用前面提到的16位序列號, 就可以很容易做到去重的效果。

超時重發的時間應該如何確定?
在理想的情況下,可以找到一個小的時間來保證 "確認應答"一定能在這個時間內返回。但是這個時間的長短,隨着網絡環境的不同是有差異的。如果超時時間設的太長,會影響整體的重傳效率。如果超時時間設的太短,有可能會頻繁發送重復的包。TCP為了保證無論在任何環境下都能比較高性能的通信,因此會動態計算這個最大超時時間。

Linux中超時時間以500ms為一個單位進行控制,每次判定超時重發的超時時間都是500ms的整數倍。如果重發一次之后,仍然得不到應答,等待2*500ms后再進行重傳。如果仍然得不到應答,等待4*500ms進行重傳。依次類推,以指數形式遞增,當累計到一定的重傳次數,TCP認為網絡或者對端主機出現異常,強制關閉連接。

連接管理機制
在正常情況下, TCP要經過三次握手建立連接,四次揮手斷開連接。

三次握手及四次揮手:https://mp.csdn.net/mdeditor/86495932

TIME_WAIT狀態: 當我們實現一個TCP服務器時,我們把這個服務器運行起來然后將服務器關閉掉,再次重新啟動服務器會發現一個問題:就是不能馬上再次綁定這個端口號和ip,需要等一會才可以重新綁定,其實等的這一會就是TIME_WAIT狀態。

TCP協議規定主動關閉連接的一方要處於TIME_ WAIT狀態,等待兩個MSL的時間后才能回到CLOSED狀態。
當我們使用Ctrl-C終止了server,server是主動關閉連接的一方在TIME_WAIT期間仍然不能再次監聽同樣的server端口。
MSL在RFC1122中規定為兩分鍾(120s),但是各操作系統的實現不同,在Centos7上默認配置的值是60s可以通過

cat /proc/sys/net/ipv4/tcp_fin_timeout查看MSL的值。

 

為什么TIME_WAIT時間一定是2MSL

首先,TIME_WAIT是為了防止最后一個ACK丟失,如果沒有TIME_WAIT,那么主動斷開連接的一方就已經關閉連接,但是另一方還沒有斷開連接,它收不到確認ACK會認為自己上次發送的FIN報文丟失會重發該報文,但是另一方已經斷開連接了,這就會造成連接不一致的問題,所以TIME_WAIT是必須的。

MSL是TCP報文在發送緩沖區的最大生存時間,如果TIME_WAIT持續存在2MSL的話就能保證在兩個傳輸方向上的尚未被接收或遲到的報文段都已經消失。(否則服務器立刻重啟,可能會收到來自上一個進程的遲到的數據,但是這種數據很可能是錯誤的)。同時也是在理論上保證最后一個報文可靠到達。(假設最后一個ACK丟失, 那么服務器會再重發一個FIN,這時雖然客戶端的進程不在了,但是TCP連接還在,仍然可以重發LAST_ACK,這就會導致問題)

 

解決TIME_WAIT狀態引起的bind失敗的方法

在server的TCP連接沒有完全斷開之前不允許重新綁定,也就是TIME_WAIT時間沒有過,但是這樣不允許立即綁定在某些情況下是不合理的:

服務器需要處理非常大量的客戶端的連接 (每個連接的生存時間可能很短,但是每秒都有很大數量的客戶 端來請求)
這個時候如果由服務器端主動關閉連接(比如某些客戶端不活躍,就需要被服務器端主動清理掉),這樣服務器端就會產生大量TIME_WAIT狀態
如果客戶端的請求量很大,就可能導致TIME_WAIT的連接數很多,每個連接都會占用一個通信五元組(源ip, 源端口, 目的ip, 目的端口, 協議)。其中服務器的ip和端口和協議是固定的,如果新來的客戶端連接的ip和端口號和TIME_WAIT占用的連接重復就造成等待。
解決方法:使用setsockopt()設置socket描述符的選項SO_REUSEADDR為1,表示允許創建端口號相同但IP地址不同的多個socket描述符。
關於setsockopt:https://www.cnblogs.com/clschao/articles/9588313.html

服務器端CLOSE_WAIT狀態: 如果客戶端是主動斷開連接的一方,在服務器端假設沒有關閉新連接,這時服務器端就會產生一個CLOSE_WAIT狀態,因為服務器沒有去關閉連接,所以這個CLOSE_WAIT狀態很容易測試出來,這時四次揮手沒有結束,只完成了兩次。

 1 #include "tcp_socket.hpp"
 2 
 3 typedef void (*Handler)(string& req, string* res);  4 
 5 class TcpServer  6 {  7 public:  8   TcpServer(string ip, uint16_t port)  9  :_ip(ip) 10  ,_port(port) 11  {} 12 
13   void Start(Handler handler) 14  { 15     //1.創建socket
16  listen_sock.Socket(); 17     //2.綁定ip和端口號
18  listen_sock.Bind(_ip, _port); 19     //3.監聽
20     listen_sock.Listen(5); 21 
22     while(1) 23  { 24  TcpSocket new_sock; 25       string ip; 26  uint16_t port; 27       //4.接收連接
28       listen_sock.Accept(&new_sock, &ip, &port); 29       cout <<"client:" << ip.c_str() << " connect" << endl; 30       while(1) 31  { 32         //5.連接成功讀取客戶端請求
33         string req; 34         bool ret = new_sock.Recv(&req); 35         cout << ret << endl; 36         if(!ret) 37  { 38           //此處服務器端不關閉新連接,導致CLOSE_WAIT狀態 39           //new_sock.Close();
40           break; 41  } 42         //6.處理請求
43         string res; 44         handler(req, &res); 45 
46         //寫回處理結果
47  new_sock.Send(res); 48         cout << "客戶:" << ip.c_str() << " REQ:" << req << ". RES:" << res << endl; 49  } 50  } 51  } 52 private: 53  TcpSocket listen_sock; 54   string _ip; 55  uint16_t _port; 56 };

 運行結果:

如果服務器上出現大量的CLOSE_WAIT狀態,原因就是服務器沒有正確的關閉 socket,導致四次揮手沒有正確完成。這是可能是一個BUG,只需要加上對應的 close即可解決問題。

 

滑動窗口

確認應答策略對每一個發送的數據段都要給一個ACK確認應答,接收方收到ACK后再發送下一個數據段,但是這樣做有一個比較大的缺點,就是性能較差,尤其是數據往返的時間較長的時候。

既然一發一收的方式性能較低,那么我們考慮一次發送多條數據,就可以大大的提高性能,它是將多個段的等待時間重疊在一起。

窗口大小指的是無需等待確認應答而可以繼續發送數據的最大值。上圖的窗口大小就是4000個字節(四個段)。發送前四個段的時候,不需要等待任何ACK直接發送即可。當收到第一個ACK后滑動窗口向后移動,繼續發送第五個段的數據,然后依次類推。操作系統內核為了維護這個滑動窗口,需要開辟發送緩沖區來記錄當前還有哪些數據沒有應答。只有確認應答過的數據,才能從緩沖區刪掉,窗口越大,則網絡的吞吐率就越高。滑動窗口左邊代表已經發送過並且確認,可以從發送緩沖區中刪除了,滑動窗口里邊代表發送出去但是沒有確認,滑動窗口右邊代表還沒有發送的數據。

如果在這種情況中出現了丟包現象,應該如何重發呢?

數據到達接收方,但是應答報文丟失:可以更具后邊的ACK確認。假設發送方發送1-1000的數據,接收方收到返回確認ACK,但是返回的ACK丟失了,另一邊發送1001-2000收到的確認ACK 2001,就可以認為1-1000數據接收成功 。

數據包之間丟失: 當某一段報文段丟失之后,發送端會一直收到 1001 這樣的ACK,就像是在提醒發送端 "我想要的是 1001" 一樣,如果發送端主機連續三次收到了同樣一個"1001" 這樣的應答,就會將對應的數據 1001 - 2000 重新發送,這個時候接收端收到了 1001 之后, 再次返回的ACK就是7001了。因為2001 - 7000接收端其實之前就已經收到了,被放到了接收端操作系統內核的接收緩沖區中。這種機制被稱為 “高速重發控制”(也叫 "快重傳")。

快重傳要求接收方在收到一個失序的報文段后就立即發出重復確認(為的是使發送方及早知道有報文段沒有到達對方)而不要等到自己發送數據時捎帶確認。快重傳算法規定,發送方只要一連收到三個重復確認就應當立即重傳對方尚未收到的報文段,而不必繼續等待設置的重傳計時器時間到期。由於不需要等待設置的重傳計時器到期,能盡早重傳未被確認的報文段,能提高整個網絡的吞吐量。

 

流量控制

接收端處理數據的速度是有限的,如果發送端發的太快,導致接收端的緩沖區被裝滿,這個時候如果發送端繼續發送,就會造成丟包,然后引起丟包重傳等等一系列連鎖反應。因此TCP支持根據接收端的處理能力,來決定發送端的發送速度,這個機制就叫做流量控制(Flow Control)。

接收端將自己可以接收的緩沖區大小放入TCP首部中的"窗口大小"字段,通過ACK確認報文通知發送端
窗口大小字段越大,說明網絡的吞吐量越高,接收端一旦發現自己的緩沖區快滿了,就會將窗口大小設置成一個更小的值通知給發送端
發送端接受到這個窗口之后,就會減慢自己的發送速度,如果接收端緩沖區滿了, 就會將窗口置為0。這時發送方不再發送數據,但是需要定期發送一個窗口探測數據段,使接收端把窗口大小告訴發送端。
接收端如何把窗口大小告訴發送端呢? 在的TCP首部中,有一個16位窗口字段,就是存放了窗口大小信息,16位數字大表示65535,那么TCP窗口大就是65535字節嗎? 實際上TCP首部40字節選項中還包含了一個窗口擴大因子M,實際窗口大小是 窗口字段的值左移M位。接收端窗口如果更新,會向發送端發送一個更新通知,如果這個更新通知在中途丟失了,會導致無法繼續通信,所以發送端要定時發送窗口探測包。

 

擁塞控制:

雖然TCP有了滑動窗口這個大殺器能夠高效可靠的發送大量的數據,但是如果在剛開始階段就發送大量的數據,仍然可能引發問題,因為網絡上有很多的計算機,可能當前的網絡狀態就已經比較擁堵,在不清楚當前網絡狀態下,貿然發送大量的數據是很有可能引起雪上加霜的,造成網絡更加堵塞。

TCP引入慢啟動機制,先發少量的數據探探路,摸清當前的網絡擁堵狀態,再決定按照多大的速度傳輸數據。

圖中的cwnd為擁塞窗口,在發送開始的時候定義擁塞窗口大小為1,每次收到一個ACK應答擁塞窗口加1。每次發送數據包的時候,將擁塞窗口和接收端主機反饋的窗口大小做比較,取較小的值作為實際發送的窗口。

像上面這樣的擁塞窗口增長速度,是指數級別的。"慢啟動"只是指初使時慢,但是增長速度非常快。為了不增長的那么快,因此不能使擁塞窗口單純的加倍,此處引入一個叫做慢啟動的閾值當擁塞窗口超過這個閾值的時候,不再按照指數方式增長, 而是按照線性方式增長。

 

當TCP開始啟動的時候,慢啟動閾值等於窗口最大值
在每次超時重發的時候,慢啟動閾值會變成原來的一半同時擁塞窗口置回1


少量的丟包,我們僅僅是觸發超時重傳。大量的丟包,我們就認為網絡擁塞。當TCP通信開始后,網絡吞吐量會逐漸上升。隨着網絡發生擁堵,吞吐量會立刻下降。擁塞控制歸根結底是TCP協議想盡可能快的把數據傳輸給對方,但是又要避免給網絡造成太大壓力的折中方案。

 


擁塞控制與流量控制的區別:

擁塞控制是防止過多的數據注入到網絡中,可以使網絡中的路由器或鏈路不致過載,是一個全局性的過程。 流量控制是點對點通信量的控制,是一個端到端的問題,主要就是權衡發送端發送數據的速率,以便接收端來得及接收。

擁塞控制的標志:

重傳計時器超時
接收到三個重復確認
擁塞避免:(按照線性規律增長)

擁塞避免並非完全能夠避免擁塞,在擁塞避免階段將擁塞窗口控制為按線性規律增長,使網絡比較不容易出現擁塞。
擁塞避免的思路是讓擁塞窗口cwnd緩慢地增大,即每經過一個往返時間RTT就把發送方的擁塞控制窗口加一。
無論是在慢開始階段還是在擁塞避免階段,只要發送方判斷網絡出現擁塞(其根據就是沒有收到確認,雖然沒有收到確認可能是其他原因的分組丟失,但是因為無法判定,所以都當做擁塞來處理),這時就把慢開始門限設置為出現擁塞時的門限的一半。然后把擁塞窗口設置為1,執行慢開始算法。

 

 


加法增大:執行擁塞避免算法后,擁塞窗口線性緩慢增大,防止網絡過早出現擁塞
乘法減小:無論是慢開始階段還是擁塞避免,只要出現了網絡擁塞(超時),那就把慢開始門限值ssthresh減半
快恢復(與快重傳配合使用)

采用快恢復算法時,慢開始只在TCP連接建立時和網絡出現超時時才使用。
當發送方連續收到三個重復確認時,就執行“乘法減小”算法,把ssthresh門限減半。但是接下去並不執行慢開始算法。
考慮到如果網絡出現擁塞的話就不會收到好幾個重復的確認,所以發送方現在認為網絡可能沒有出現擁塞。所以此時不執行慢開始算法,而是將cwnd設置為ssthresh的大小,然后執行擁塞避免算法。


延遲應答

如果接收數據的主機立刻返回ACK應答,這時候返回的窗口可能比較小。假設接收端緩沖區為1M 一次收到了500K的數據。如果立刻應答,返回的窗口就是500K。 但實際上可能處理端處理的速度很快,10ms之內就把500K數據從緩沖區消費掉了,在這種情況下,接收端處理還遠沒有達到自己的極限,即使窗口再放大一些也能處理過來。如果接收端稍微等一會再應答,比如等待200ms再應答,那么這個時候返回的窗口大小就是1M。

窗口越大,網絡吞吐量就越大,傳輸效率就越高。我們的目標是在保證網絡不擁塞的情況下盡量提高傳輸效率。

數量限制: 每隔N個包就應答一次
時間限制: 超過大延遲時間就應答一次
注:具體的數量和超時時間, 依操作系統不同也有差異; 一般N取2, 超時時間取200ms

 

捎帶應答

在延遲應答的基礎上,存在很多情況下,客戶端服務器在應用層也是"一發一收" 的。 意味着客戶端給服務器說了"How are you", 服務器也會給客戶端回一個"Fine, thank you"。那么這個時候ACK就可以搭順風車,和服務器回應的 "Fine, thank you" 一起回給客戶端

 

面向字節流

當我們創建一個TCP的socket,同時在內核中創建一個發送緩沖區和一個接收緩沖區。

調用write時,內核將數據會先寫入發送緩沖區中,如果發送的字節數太長,會被拆分成多個TCP的數據包發出,如果發送的字節數太短,就會先在緩沖區里等待, 等到緩沖區長度達到設置長度,然后等到其他合適的時機發送出去。
調用read接收數據的時候, 數據也是從網卡驅動程序到達內核的接收緩沖區。然后應用程序可以調用read從接收緩沖區拿數據。TCP的一個連接,既有發送緩沖區, 也有接收緩沖區,那么對於這一個連接,既可以讀數據,也可以寫數據。所以是全雙工的。
由於緩沖區的存在,TCP程序的讀和寫不需要一一匹配。例如: 寫100個字節數據時, 可以調用一次write寫100個字節, 也可以調用100次write, 每次寫一個字節; 讀100個字節數據時, 也完全不需要考慮寫的時候是怎么寫的, 既可以一次read 100個字節, 也可以一次 read一個字節, 重復100次

 

粘包問題

粘包問題中的 "包"是指的應用層的數據包。在TCP的協議頭中,沒有如同UDP一樣的 "報文長度"這樣的字段,但是有一個序號這樣的字段。站在傳輸層的角度, TCP是一個一個報文過來的,按照序號排好序放在緩沖區中,但是站在應用層的角度,它看到的只是一串連續的字節數據。應用程序看到了這么一連串的字節數據, 就不知道從哪個部分開始到哪個部分結束是一個完整的應用層數據包,這就是粘包問題。

如何避免粘包問題呢?明確兩個包之間的邊界

對於定長的包,保證每次都按固定大小讀取即可。例如一個Request結構, 是固定大小的, 那么就從緩沖區從頭開始按sizeof(Request)依次讀取即可
對於變長的包,可以在包頭的位置,約定一個包總長度的字段,從而就知道了包的結束位置。
對於變長的包,還可以在包和包之間使用明確的分隔符(應用層協議是程序員自己來定義的, 只要保證分隔符不和正文沖突即可)。
對於UDP協議,如果還沒有上層交付數據, UDP的報文長度仍然在。 同時UDP是一個一個把數據交付給應用層,這樣就有存在明確的數據邊界,站在應用層的角度, 使用UDP的時候要么收到完整的UDP報文要么不收,不會出現"半個"的情況。

 

TCP連接異常情況

進程終止:進程終止會釋放文件描述符,仍然可以發送FIN,和正常關閉沒有什么區別。機器重啟和進程終止一樣。
機器掉電/網線斷開:接收端認為連接還在,一旦接收端有寫入操作,接收端發現連接已經不在了,就會進行reset。即使沒有寫入操作,TCP自己也內置了一個保活定時器,會定期詢問對方是否還在。如果對方不在,也會把連接釋放。應用層的某些協議, 也有一些這樣的檢測機制.例如HTTP長連接中, 也會定期檢測對方的狀態.Q在QQ 斷線之后, 也會定期嘗試重新連接。
————————————————
版權聲明:本文為CSDN博主「Hansionz」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/hansionz/article/details/86435127

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM