【Linux網絡編程】傳輸層協議TCP,UDP

目錄

一,UDP協議

1,UDP協議的格式

2,UDP的特點?

3,面向數據報

4,UDP的緩沖區

5,UDP使用注意事項

6,基于UDP的應用層協議

二,對于報文的理解

三,TCP協議

1,TCP協議格式

2,可靠性的本質

(1) 確認應答(ACK)機制

(2)序號和確認序號?

?(3)超時重傳機制

(4)流量控制?

(5)六個標志位

(6)連接管理機制?

【 三次握手 】

【 四次揮手 】

(7)滑動窗口

【理解滑動窗口】

?【丟包問題】

(8)擁塞控制

(9)延遲應答

(10)面向字節流

(11)粘包問題

(12)TCP異常情況

四,TCP小結


前言:

傳輸層是實現端到端通信的核心,主要涉及TCP和UDP

一,UDP協議

1,UDP協議的格式

16位UDP長度,表示整個數據報(UDP首部+UDP數據)的最大長度。

如果校驗和出錯,則會直接丟棄該報文。

2,UDP的特點?

無連接:直到對端的IP和端口號就直接進行傳輸,不需要建立連接。

不可靠:沒有確認機制,沒有重傳機制;如果因為網絡故障數據無法發送到對方,UDP協議層也不會給應用層返回任何信息。

面向數據報:不能夠靈活的控制讀寫數據的次數;

3,面向數據報

應用層交給UDP多長的報文,UDP原樣發送,既不會拆分,也不會合并。

比如用UDP傳輸100個字節的數據:

如果發送端調用一次sendto,發送100個字節。那么接受端必須調用一次recvfrom,接受100個字節的數據;而不能循環調用10次recvform,每次接受10個字節的數據。

4,UDP的緩沖區

對于TCP,上層在調用write發送數據的時候,本質是將數據拷貝到TCP的發送緩沖區中,什么時候發,發多少由操作系統據決定。發送發將數據發送給對端,本質是將數據拷貝到對端的接受緩沖區中,對端在調用 read讀取數據的時候,本質是從接受緩沖區中讀取數據。

所以TCP有兩個緩沖區:發送緩沖區和接受緩沖區。

而對于UDP而言,是不需要發送緩沖區,它只有一個接受緩沖區。在調用sendto發送數據的時候,會直接將數據交給內核,由內核將數據交給網絡層進行后序的傳輸動作。

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

5,UDP使用注意事項

UDP協議首部有一個16位的最大長度,也就是說一個UDP能傳輸的數據報的最大長度是64KB(包含UDP首部)。

然而64KB在當前的互聯網環境下,是一個非常小的數字。

如果我們需要傳輸的數據超過64KB,就需要在應用層手動的進行分包,多次發送,并在接收端手動拼裝。

6,基于UDP的應用層協議

NFS:網絡文件系統

TFTP:簡單文件傳輸系統

DHCP:動態主機配置協議

DNS:域名解析協議

二,對于報文的理解

操作系統是基于中斷運行的,如果應用層正在進行報文的解析,到收到新的報文時,外圍設備就緒觸發中斷,操作系統就會從設備中(網卡)讀取數據,拿到數據報。

那么此時操作系統中一定會存在大量的報文,所以操作系統就需要對這些報文進行管理。如何管理?先描述,再組織:

sk_buff結構就是用來描述一個數據報的。在Linux內核中的部分源代碼如下:

struct  sk_buff{struct sk_buff* next;struct sk_buff* prev;//……//…… unsigned char   *head,*data,*tail,*end;
}

sk_buff結構中重要的4個指針指向一段緩沖區 ?。有點類似于進程PCB和進程對應的代碼和數據。

當數據報詳細交付時,當從應用層交付到傳輸層時,data指針向上移動一段空間,如果使用UDP協議,移動UDP報頭的大小,然后填充對應UDP報頭。如果使用TCP協議,移動一個TCP報頭的大小,然后填充 TCP報頭。當數據報從傳輸層交付到網絡層時,data指針向上移動,然后再填充上對應的報頭 ,依次類推。

如果是向上層移動,那么就是data指針向下移動。

所以,對于數據報的解包和分用,其實就是 data指針在對應 緩沖區中的指向!!!

三,TCP協議

tcp協議,全稱為"傳輸控制協議"。人如其名,要對數據的傳輸進行 詳細的控制。

1,TCP協議格式

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

16位校驗和:發送端填充,CRC校驗,接收端不通過,則認為數據有問題。此處的校驗,不僅包含TCP首部,也包含TCP數據部分。

4位首部長度:表示TCP報頭的大小(包含選項),單位是4字節。比如,1111表示15,對應的報頭大小為15*4=60字節。又因為TCP報頭大小至少為20字節(不包含選項),所以4位首部長度最小的數值是5,最大是15.

在TCP報文的格式中,沒有對應的數據部分的大小,只有報頭的大小。

而UDP報文中記錄了整個報文的大小,通過減去報頭的大小,我們就可以獲取到對應數據的大小。所以,對于UDP報文,數據和數據之間的邊界是很明顯的。

而在TCP中,是沒有的,也是不需要有的。因為TCP不能保證接受上來的報文就是一個完整的請求,它將接受到的報文去掉報頭,放入到接受緩沖區中,上層進行讀取數據,由上層自己判斷是不是一個完整的請求。而UDP可以保證,它接受上來的報文就是一個完整的請求。

所以說UDP是面向數據報的,TCP是面向字節流的。

2,可靠性的本質

(1) 確認應答(ACK)機制

在兩臺主機通過TCP進行通信的時候,如上圖,主機A給主機B發送數據,主機A發送了數據,但是無法確定主機B是否成功收到了數據,此時需要主機B的操作系統給主機A發送一個應答報文。?表示主機B收到了數據,這個應答報文沒有數據部分,并且6個標志位中的ACK設為1。表示該報文是一個應答報文。

注:應答是由操作系統自己完成的。主機B在接收到數據后,主機B的操作系統會自動構建一個應答報文返回給主機B。

?但是有時候主機B也要給主機A發送數據,所以在主機B給主機A發送數據的時候,會攜帶上應答。

這種應答方式稱為捎帶應答

(2)序號和確認序號?

?當主機A向主機 B發送數據的時候,在TCP報頭部分會填充上序號的值,同時主機B在做應答的時候,會根據序號,計算出確認序號。確認序號=序號+1。

對于主機A,也就是發送端,會收到應答報文(或者捎帶應答),比如收到確認序號為2001的應答報文,主機A就會認為序號為2001之前的所有報文,對端已經全部收到了。這種方式可以大大提高數據傳輸的效率。

對于主機B,也就是接收端。當主機A發送數據的時候,每個數據到達主機B的時間可能不同,有的報文發的早,但是到達主機B的時間晚,有的報文發的晚,但是到達主機B的時間早。通過序號,可以將收到的報文進行排序,并且實現去重的目的(有的數據報可能會發送多次)。

?(3)超時重傳機制

主機A給主機B發送數據之后,可能因為網絡擁堵等原因,數據無法到達主機B。

如果主機A在特定的時間間隔內沒有收到B發來的確認應答,就會重發數據。

但是,主機A未收到主機B發來的應答時,也可能是因為應答(ACK)丟失了。?

?此時主機A仍然會進行超時重傳,所以主機B就會收到多個重復的數據報。TCP協議是可以區分出來這些重復的數據報的(通過序號,很容易做到去重的效果),并且把重復的丟棄掉。

超時的時間是如何確定的???

  • 最理想的情況是,找一個最小的時間,保證"確認應答"一定能在這個事件內到達。
  • 但是這個時間的長短,隨著網絡環境的不同,是有差異的。
  • 如果超時重傳時間設的太長,會影響整體的重傳效率。
  • 如果超時時間設的太短,有可能會頻繁發送重復的包。

這個時間應該和網絡當前的狀態是有關的。而網絡狀態時刻在變化,所以這個值應該也是一個變化的。

TCP為了保證無論在任何環境下都能夠比較高效的通信,因此一般會動態計算這個超時時間。

Linux中(BSD Unix和Windows也是如此),超時以500ms為一個單位 進行控制,每次判定超時重發的超時時間都是500ms的整數倍。

  • 如果重發一次后,仍然得不到應答,等待2*500ms再進行重傳。
  • 如果仍然得不到應答,等待4*500ms再重傳,依次類推,以指數形式遞增。
  • 累積到一定的重傳次數,TCP認為網絡或對端主機出現異常,強制關閉連接。

(4)流量控制?

前面提到過,TCP有發送緩沖區和接受緩沖區。

  • 上層在調用write接口發送數據時,實際是把數據拷貝到對應的發送緩沖區,什么時候發,發多少由操作系統決定。將數據發送到對端的接受緩沖區中。
  • 上層在調用read接口讀取數據時,實際是把數據從 接受緩沖區中讀上來,如果接受緩沖區為空,則會在read接口處阻塞住。

當發送方 發送數據的時候,對端(接收方)的接受緩沖區可能滿了,放不下數據了?。那么此時對端在收到數據后,就會將該數據直接丟棄。

這是不合理的,因為數據報在網絡傳輸中會消耗電力,帶寬等等網絡資源。如果直接丟棄,這就是一種浪費資源的現象。

為了解決這種問題,發送方就需要知道對端的接受能力,也就是對端接受緩沖區剩余空間的大小。從而決定發送多少數據。

在TCP報頭中,16位窗口大小,該字段就表示對端的接受能力的大小。這種機制叫做流量控制

那么問題來了,16位表示的最大數字是65535,那么TCP接受緩沖區最大就是65535字節嗎???

實際上,TCP首部40字節選項中還包含一個窗口擴大因子M,實際窗口大小是窗口字段的值左移M位。

通過流量控制機制,一方面可以提高TCP傳輸的可靠性,另一方面,可以提高傳輸的效率。?

(5)六個標志位

在TCP報頭中,存在六個標志位:URG,ACK,PSH,RST,SYN,FIN

首先,在使用TCP進行通信的時候,雙方需要先建立連接。(三次握手)

雙方結束通信的時候,需要釋放對應連接。(四次揮手)

三次握手和四次揮手重點在連接管理機制部分說明。

這六個標志位,在TCP報頭中對應一個比特位,要么為0,要么為1。為1表示給標志生效。

SYN:同步標志位,請求建立連接,握手過程使用 的標志位。

ACK:確認序號是否有序。ACK為1,表示該報文是一個應答報文(或者捎帶應答)。

PSH:提示接受端應用程序立刻從TCP緩沖區把數據讀走。

RST:對方要求重新建立連接。我們 把攜帶RST的報文稱為復位報文段

?FIN:通知對方,本端要關閉連接了,我們稱攜帶FIN標識的為結束報文段。

URG:標識TCP報頭中的16位緊急指針是否有效。如果將URG設置為1,表示當前報文中包含緊急數據,需要將該報文立即交給上層處理。

舉個例子:

當我們使用百度網盤上傳文件時,將數據發送到服務器的接受緩沖區中。

上傳過程中,如果發現上傳錯了,想要取消上傳。取消上傳也是以報文的形式發送給服務器的。

此時就希望服務器立馬處理這個報文。而不是先將該報文放到接受緩沖區中,當前面的報文處理完了,才處理該報文。

所以此時就可以將URG置為1,表示該報文是一個 緊急報文,需要立即處理。

暫停上傳也是類似的思路。

實際上,為了實現這個功能,不一定非要使用URG標志位,也可以通過建立兩條連接的方式,一條連接用來發送數據,另一條連接用來發送指令。

URG為1時,表示16位緊急指針有效,假設該16位有效指針表示的數字是n。意味著在該報文有效載荷中,偏移量為n處,有緊急數據,該緊急數據的大小是一個字節。這個緊急數據本身就是一個標志位,比如,標志位為1表示取消,標志位為2表示暫停等等。?

(6)連接管理機制?

正常情況下,TCP要通過三次握手建立連接,通過四次揮手斷開連接。

?

上圖中,諸如SYN_SENT,ESTABLISHED,FIN_WAIT1等等,都表示的是當前服務器或者客戶端所處的狀態,其本質就是一個數字,?通過宏定義出來的。

【 三次握手 】

三次握手的大致過程:客戶端發起建立連接的請求SYN,服務器收到請求后。向客戶端發送ACK(確認應答 ),表示收到請求了。同時服務器端向客戶端發送建立連接的請求(SYN),這兩個合成一個報文。最后,客戶但發送ACK(確認應答),表示收到請求了。至此建立連接完成,三次握手成功。

客戶端調用connect發起三次握手,向服務器發起建立連接的請求。而服務器端通過listen將自己設置為監聽狀態。

本質上,connect是發起三次握手,但是不參與三次握手的。服務器端通過accept獲取底層建立好的連接,也不參與三次握手。三次握手由雙方客戶端和服務器端操作性系統自動完成。

為什么要進行三次握手???

1,通過三次握手,可以以最短的方式進行驗證雙方的全雙工通信。本質是驗證雙方所處的網絡是否通常,是否能夠支持全雙工。

2,以最小的成本,100%確認雙方通信的意愿。

【 四次揮手 】

四次揮手的大致過程:通信雙方斷開連接的過程。客戶端發送FIN,表示本端想要關閉連接,服務器端收到后發送確認應答(ACK)。接著服務器端也發送FIN,表示本段也想要關閉連接,客戶端收到后,發送確認應答(ACK),服務器端收到應答。至此,四次揮手完成,雙方斷開連接。

四次揮手也是由操作系統自動完成的。本質是建立雙方斷開連接的共識。客戶端(服務端)認為要發送的數據已經發送完了,調用close(fd)斷開連接。?

在三次握手中,將SYN+ACK合并了,本質上是4次握手,降級成了三次握手。

而對于四次揮手,不一定能進行合并,當客戶端數據發送完了,向服務器發送斷開連接的請求時,服務器先要回復一個確認應答(ACK),但此時由于服務器要發送的數據可能還沒發完,所以服務器要等待一段時間,將這些數據全部發送完,才會向客戶端發起斷開連接的請求,客戶端收到后向服務器發送確認應答(ACK)。至此,雙方完成斷開連接。因此,對于斷開連接的過程,中間兩步一般無法合并成 一次,所以大部分情況下是四次揮手。

TIME_WAIT狀態:

關于四次揮手,還有一個細節,下圖中,客戶端主動發起斷開連接,四次揮手完成后最后客戶端會先處于TIME_WAIT狀態,而不是立即處于CLOSED狀態,經過一段時間,才會處于CLOSED狀態。而對于服務器端,四次揮手完成后,會立即處于CLOSED狀態。

這是因為,TCP協議規定:主動關閉連接的一方要先處于TIME_WAIT狀態,等待兩個MSL(maximum segment lifetime)的時間后才能會得到CLOSED狀態。MSL是TCP報文的最大生存時間。

原因:當通信雙方想要斷開連接的時候,歷史發出的報文可能還在網絡中進行轉發,還沒到達接收端,這時雙方關閉連接。當雙方重新建立連接的時候,這個在網絡中殘留的報文此時可能就會到來,根據目的IP和目的端口找到對應的主機,但此時連接都還沒建立,三次握手都還沒完成。所以這個報文是會影響 通信雙方重新建立連接和發送數據的,等待2個MSL是為了讓這個報文在網絡中消散。

  • 當雙方在通過網絡TCP進行通信的時候,如果有一方主動斷開連接,會進入TIME_WAIT狀態。在該狀態下,無法重新啟動程序,bind會失敗,因為之前的端口號還在被占用
  • 比如:我們使用 Ctrl-C 終止了 server, 所以 server 是主動關閉連接的一方, TIME_WAIT 期間仍然不能再次監聽同樣的 server 端口;需要更換端口號,或者等待TIME_WAIT狀態結束

站在應用角度,一般都是既要實現TIME_WAIT,還要服務器可以立即重啟。

使用 setsockopt()設置 socket 描述符的 選項 SO_REUSEADDR 為 1, 表示端口號復用。

? ? ? ?int setsockopt(int sockfd, int level, int optname,
? ? ? ? ? ? ? ? ? ? ? const void *optval, socklen_t optlen);

  • 使用這種方式可以使程序立即重啟,但是也可能會造成歷史報文對雙方通信的影響,但是 TCP為了解決這一問題,還有一個"后背隱藏能源"——序號。接收端還會根據序號來判斷這個 報文是否有效。
  • 通信雙方在三次握手的時候,會完成序號和確認序號的協商,比如客戶端發送報文的序號從1000開始,接收端發送應答報文的確認序號從2000開始。當一段收到的序號發現不匹配時,就會將該報文丟棄掉。

TIME_WAIT+序號,通過以上的處理方式,就可以大大減少陳舊報文對新連接建立產生的影響。

(7)滑動窗口

【理解滑動窗口】

在上面我們討論了確認應答機制,對每一個發送的數據段,都需要給一個ACK應答。收到ACK后再發送下一個數據段。這樣做有一個比較大的缺點,就是性能較差,尤其是數往返時間較長的時候。

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

主機A向主機B發送數據,1~1000表示的是數據的大小,當發送的數據大小是1~1000時,序號就是1000,主機B收到后,進行應答,確認序號=序號+1,所以確認序號就是1001,同時下一個數據從1001開始發送,選后是依次增大的。發送前4個報文的時候,不需要等待ACK,可以直接發送。


滑動窗口大小指的是無需等待確認應答而可以繼續發送數據的最大值。

在前面提到過,TCP有自己的接受緩沖區和發送緩沖區。如下圖所示:

我們可以將發送緩沖區看成是一個char類型的數組,滑動窗口看成是發送緩沖區的一部分 。start指向滑動窗口的開始,end指向滑動窗口的結束。

根據滑動窗口,可以將發送緩沖區劃分為三部分:

  • 對于已發送已確認的數據:其實不需要真正將這部分空間清空。本質是這部分數據無效了,可以再次 被利用了。不需要可以的去清空 緩沖區。
  • 對于滑動窗口:可以直接發送 ,暫時不需要應答。滑動窗口的大小由對端的接受緩沖區剩余空間的大小決定(還有一個因素,在擁塞控制部分講解)。滑動窗口移動的本質:strat和end下標增加。所以,滑動窗口的大小決定一次可以直接發多少的數據。
  • 滑動窗口是流量控制的具體實現方案。
  • 窗口越大,證明當前網絡的吞吐率越高。

滑動窗口大致工作過程如下圖:

注意:窗口大小是可能會改變的,變大或者變小,取決于對方的接受能力。?

?【丟包問題】

發送端在發送數據的時候,可能會存在丟包問題。

大致分為三種:滑動窗口最左側丟失,中間丟失,最右側丟失。

如果中間報文丟失,那么滑動窗口首先會向右滑動,滑倒丟失的位置,此時就又變成了最左側丟失問題。如果最右側報文丟失,同理,也是最左側丟失問題。


最左側丟失,又分為兩種情況,最左側對應的應答丟失,最左側對應的數據真的丟了。

  1. 最左側報文真的丟了,滑動窗口左側不變。
  2. 應答丟失,滑動窗口正常工作。

情況一:數據包真的丟失了

  1. 當1001~2000的報文丟失后,發送端會一直接受到1001這樣的ACK應答,就像是在提醒發送端"我想要1001一樣"。
  2. 如果發送端主機連續三次收到同一個1001這樣的應答報文后,就會將對應的數據進行重傳。
  3. 這個時候,接收端再收到1001之后,再次返回的ACK就是7001了(因為2001~7000接受端之前已經收到了,被放到了接收端操作系統內核的接收緩沖區中。

這種機制被稱為 "高速重發控制"(也叫 "快重傳")。

上述的情況只能確認1001~2000的報文丟失了,不能確定中間的是否丟失了。假設中間的4001~5000也丟失了,由于我們的通信一直再進行著,比如我們下面還會發送7001~8000,8001~9000的數據,那么此時的確認應答就是40001。也就是如果中間部分丟失了,會有后面的通信做兜底。同時,還有超時重傳機制來確保。

快重傳vs超時重傳

快重傳:收到三個相同的確認應答時進行重傳,可以提高效率。

超時重傳:超時并且沒有收到應答,用來做兜底的。

?總結:發出數據后,沒有收到應答 ,必須讓對應的報文暫時保存起來,以方便后續的而重傳!

保存在滑動窗口中,也就是左側不移動。

情況二:數據已抵達,ACK丟失

這種情況下, 部分 ACK 丟了并不要緊, 因為可以通過后續的 ACK 進行確認。

因為確認序號的定義就是該序號之前的所有報文對端都已經收到了。 所以,滑動窗口可以正常進行工作。

(8)擁塞控制

雖然TCP有了滑動窗口這個大殺器,能夠高效可靠的發送大量數據,但是如果一開始發送大量的數據,也可能會出現問題。

因為網絡上又很多計算機,可能當前的網絡狀態已經很擁堵了。在不清楚當前網絡狀態的前提下,貿然發送大量數據,是很有可能造成雪上加霜的。

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

為了衡量當前網絡的擁塞狀態,TCP引入了一個新的概念——擁塞窗口。

剛開始發送數據的時候,擁塞窗口大小為2^0。

當收到一個ACK應答時,擁塞窗口大小為2^1。

以此類推,2^2,2^3......呈現指數形式增長。如下圖所示:

在前面滑動窗口 部分提到過,滑動 窗口的大小是對方接受能力的大小(也是就是對端緩沖區剩余空間的大小),現在再加一個因素,就是擁塞窗口的大小。取兩者的最小值。

滑動窗口大小=min(對端接受能力大小,擁塞控制大小),之所以取最小值,是因為對端接受能力很強,但是網絡太擁堵了,發送太多數據會造成大量的丟包;同理,網絡狀態很好,但是對端接受能力太差,同樣發送給大量數據也會造成大面積丟包。


但是關于 擁塞窗口的大小,不能一直這么增長下去,因為可能會造成指數爆炸,需要通過慢啟動機制來控制。

  1. 使用指數增長,剛開始時窗口大小較小,但是增長速度很快。
  2. 此處引入一個慢啟動的閾值(下圖中的ssthresh)。
  3. 當擁塞窗口大小超過這個閾值的時候,不會再按照指數形式增長,而是按照線性方式增長。

前面指數增長階段,本質是解決擁塞,嘗試回復網絡通信的階段。

剛開始擁塞窗口一直在增加,但是發送的數據不一定一直在增長。

當擁塞窗口大小一直再增大,增大到某一個數值時,此時發送數據發送大量丟包,那么說明此時的擁塞窗口大小就是當前網絡的擁塞狀況。這個過程就是我們 在探測當前網絡的擁塞情況。之后,重新開始滿開始 增長,此時的閾值就是上次擁塞窗口值的一半。

?這整個過程本質是不斷探測當前網絡的擁塞窗口的值。

(9)延遲應答

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

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

(10)面向字節流

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

  • 調用 write 時, 數據會先寫入發送緩沖區中;
  • 如果發送的字節數太長, 會被拆分成多個 TCP 的數據包發出;
  • 如果發送的字節數太短, 就會先在緩沖區里等待, 等到緩沖區長度差不多了, 或者其他合適的時機發送出去;
  • 接收數據的時候, 數據也是從網卡驅動程序到達內核的接收緩沖區;
  • 然后應用程序可以調用 read 從接收緩沖區拿數據;
  • 另一方面, TCP 的一個連接, 既有發送緩沖區, 也有接收緩沖區, 那么對于這一個連接, 既可以讀數據, 也可以寫數據. 這個概念叫做 全雙工。

由于緩沖區的存在, TCP 程序的讀和寫不需要一一匹配, 例如:

寫 100 個字節數據時, 可以調用一次 write 寫 100 個字節, 也可以調用 100 次

write, 每次寫一個字節。讀 100 個字節數據時, 也完全不需要考慮寫的時候是怎么寫的,既可以一次
read 100 個字節, 也可以一次 read 一個字節, 重復 100 次;

(11)粘包問題

首先要明確, 粘包問題中的 "包" , 是指的應用層的數據包.

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

那么如何避免粘包問題呢? 歸根結底就是一句話, 明確兩個包之間的邊界.

  • 對于定長的包, 保證每次都按固定大小讀取即可;?
  • 對于變長的包, 可以在包頭的位置, 約定一個包總長度的字段, 從而就知道了包的結束位置;
  • 對于變長的包, 還可以在包和包之間使用明確的分隔符(應用層協議, 是程序猿自己來定的, 只要保證分隔符不和正文沖突即可);

對于 UDP 協議來說, 是否也存在 "粘包問題" 呢?

  • 對于 UDP, 如果還沒有上層交付數據, UDP 的報文長度仍然在. 同時, UDP 是一個一個把數據交付給應用層. 就有很明確的數據邊界.
  • 站在應用層的站在應用層的角度, 使用 UDP 的時候, 要么收到完整的 UDP 報文, 要么不收. 不會出現"半個"的情況。

(12)TCP異常情況

  • 進程終止: 進程終止會釋放文件描述符, 仍然可以發送 FIN. 和正常關閉沒有什么區別.
  • 機器重啟: 和進程終止的情況相同.
  • 機器掉電/網線斷開: 接收端認為連接還在, 一旦接收端有寫入操作, 接收端發現連接已經不在了, 就會進行 reset. 即使沒有寫入操作, TCP 自己也內置了一個保活定時器, 會定期詢問對方是否還在. 如果對方不在, 也會把連接釋放。
  • 另外, 應用層的某些協議, 也有一些這樣的檢測機制. 例如 HTTP 長連接中, 也會定期檢測對方的狀態. 例如 QQ, 在 QQ 斷線之后, 也會定期嘗試重新連接。

四,TCP小結

為什么 TCP 這么復雜? 因為要保證可靠性, 同時又盡可能的提高性能。

可靠性:

  • 校驗和
  • 序列號(按序到達)
  • 確認應答
  • 超時重發
  • 連接管理
  • 流量控制
  • 擁塞控制

提高性能:

  • 滑動窗口
  • 快速重傳
  • 延遲應答
  • 捎帶應答

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/83776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83776.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/83776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Neo4j 數據可視化與洞察獲取:原理、技術與實踐指南

在關系密集型數據的分析領域,Neo4j 憑借其強大的圖數據模型脫穎而出。然而,將復雜的連接關系轉化為直觀見解,需要專業的數據可視化技術和分析方法。本文將深入探討 Neo4j 數據可視化的核心原理、關鍵技術、實用技巧以及結合圖數據科學庫(GDS)獲取深度洞察的最佳實踐。 Ne…

樹莓派超全系列教程文檔--(55)如何使用網絡文件系統NFS

如何使用網絡文件系統NFS 網絡文件系統 (NFS)設置基本 NFS 服務器Portmap 鎖定(可選) 配置 NFS 客戶端端口映射鎖定(可選) 配置復雜的 NFS 服務器組權限DNS(可選,僅在使用 DNS 時)NIS&#xff0…

無法運用pytorch環境、改環境路徑、隔離環境

一.未建虛擬環境時 1.創建新項目后,直接運行是這樣的。 2.設置中Virtualenv找不到pytorch環境?因為此時沒有創建新虛擬環境。 3.選擇conda環境(全局環境)時,是可以下載環境的。 運行結果如下: 是全局環境…

HTML5+CSS3+JS小實例:具有粘性重力的磨砂玻璃導航欄

實例:具有粘性重力的磨砂玻璃導航欄 技術棧:HTML+CSS+JS 效果: 源碼: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width…

NodeJS全棧WEB3面試題——P8項目實戰類問題(偏全棧)

&#x1f4e6; 8.1 請描述你做過的 Web3 項目&#xff0c;具體技術棧和你負責的模塊&#xff1f; 我主導開發過一個基于 NFT 的數字紀念平臺&#xff0c;用戶可以上傳照片并生成獨特的紀念 NFT&#xff0c;結合 IPFS 和 ERC-721 實現永存上鏈。 &#x1f527; 技術棧&#xf…

3-10單元格行、列號獲取(實例:表格選與維度轉換)學習筆記

************************************************************************************************************** 點擊進入 -我要自學網-國內領先的專業視頻教程學習網站 *******************************************************************************************…

AI問答-vue3+ts+vite:http://www.abc.com:3022/m-abc-pc/#/snow 這樣的項目 在服務器怎么部署

為什么記錄有子路徑項目的部署&#xff0c;因為&#xff0c;通過子路徑可以區分項目&#xff0c;那么也就可以實現微前端架構&#xff0c;并且具有獨特優勢&#xff0c;每個項目都是絕對隔離的。 要將 Vue3 項目&#xff08;如路徑為 http://www.abc.com:3022/m-saas-pc/#/sno…

PostgreSQL-基于PgSQL17和11版本導出所有的超表建表語句

最新版本更新 https://code.jiangjiesheng.cn/article/368?fromcsdn 推薦 《高并發 & 微服務 & 性能調優實戰案例100講 源碼下載》 1. 基于pgsql 17.4 研究 查詢psql版本&#xff1a;SELECT version(); 查看已知1條建表語句和db中數據關系 SELECT create_hypert…

世事無常,比較復雜,人可以簡單一點

2025年6月5日日&#xff0c;17~28℃&#xff0c;一般 待辦&#xff1a; 宣講會 職稱材料的最后檢查 職稱材料有錯誤&#xff0c;需要修改 期末考試試題啟用 教學技能大賽PPT 遇見&#xff1a;部門宣傳泰國博士項目、碩士項目、本科項目。 感受或反思&#xff1a;東南亞博士…

B站緩存視頻數據m4s轉mp4

B站緩存視頻數據m4s轉mp4 結構分析 結構分析 在沒有改變數據存儲目錄的情況下&#xff0c;b站默認數據保存目錄為&#xff1a; Android->data->tv.danmaku.bili->download每個文件夾代表一個集合的視頻&#xff0c;比如&#xff0c;我下載的”java從入門到精通“&…

一次Oracle的非正常關閉

數據庫自己會關閉嗎&#xff1f; 從現象來說Oracle MySQL Redis等都會出現進程意外停止的情況。而這些停止都是非人為正常關閉或者暴力關閉&#xff08;abort或者kill 進程&#xff09; 一次測試環境的非關閉 一般遇到這種情況先看一下錯誤日志吧。 2025-06-01T06:26:06.35…

linux 串口調試命令 stty

linux 串口調試命令 stty 文章目錄 linux 串口調試命令 sttystty 常見命令選項&#xff1a;常用參數&#xff1a;一次性設置串口所有常見參數總結 stty&#xff08;設置終端行模式&#xff09;命令是用來配置終端設備&#xff08;包括串口設備&#xff09;的輸入和輸出行為的工…

【地址區間劃分】

地址區間劃分 1 decode_addr1.1 地址區間1.2 變式 本篇博客主要介紹對地址區間劃分的一個比較巧妙參數化的做法。 1 decode_addr 遇到一個master轉多個slave時&#xff0c;不可避免需要進行對addr總線進行分配地址區間來進行選中&#xff1b; 在這里給出一個可復用且設計思想比…

mysql復合查詢mysql子查詢

基礎表結構創建 表結構包含主外鍵約束和字符集配置&#xff0c;確保數據完整性 部門表 CREATE TABLE dept (deptno int NOT NULL COMMENT 部門編號,dname varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 部門名稱,loc varchar(20) CHARACTE…

vlan(虛擬局域網)邏輯圖解+實驗詳解

VLAN&#xff08;Virtual Local Area Network&#xff0c;虛擬局域網&#xff09; 是一種通過邏輯方式&#xff08;非物理連接&#xff09;將網絡設備劃分為多個獨立廣播域的技術。它允許管理員在同一個物理網絡中創建多個隔離的虛擬網絡&#xff0c;從而提升網絡的安全性、靈…

2025年—Comfy UI 和 Stable Diffusion底層原理

為什么要先講SD原理 &#xff1f; 邏輯理解: ComfyUI是節點式操作&#xff0c;需要自行搭建工作流&#xff0c;理解原理才能靈活定制工作流學習效率: 基礎原理不懂會導致后續學習吃力&#xff0c;原理是掌握ComfyUI的關鍵核心價值: ComfyUI最有價值的功能就是自主搭建工作流&a…

深入理解C#中的Web API:構建現代化HTTP服務的完整指南

在當今的軟件開發領域&#xff0c;構建高效、可擴展的Web服務已成為一項基本需求。作為.NET開發者&#xff0c;C#中的Web API框架為我們提供了創建RESTful服務的強大工具。本文將全面探討Web API的核心概念、實現細節和最佳實踐&#xff0c;幫助您掌握這一關鍵技術。 一、Web A…

起重機指揮人員在工作中需要注意哪些安全事項?

起重機指揮人員在作業中承擔著協調設備運行、保障作業安全的關鍵職責&#xff0c;其安全操作直接關系到整個起重作業的安全性。以下從作業前、作業中、作業后的全流程&#xff0c;詳細說明指揮人員需注意的安全事項&#xff1a; 一、作業前的安全準備 資質與狀態檢查&#xff…

【高等數學】傅里葉級數逼近例子

f ( x ) π 2 ? ∣ x ∣ f(x)\frac{\pi}{2}-|x| f(x)2π??∣x∣ 由于是偶函數只需要求 cos ? ( n x ) , 1 \cos(nx),1 cos(nx),1 的系數 a n 0 a_n 0 an?0, n n n 是偶數 a n 1 ( 2 n ? 1 ) 2 a_n \frac{1}{(2n-1)^2} an?(2n?1)21?, n n n 是奇數 則 f ( x )…

PowerBI企業運營分析—全動態盈虧平衡分析

PowerBI企業運營分析—全動態盈虧平衡分析 歡迎來到Powerbi小課堂&#xff0c;在競爭激烈的市場環境中&#xff0c;企業運營分析平臺成為提升競爭力的核心工具。 該平臺通過整合多源數據&#xff0c;實現關鍵指標的實時監控&#xff0c;從而迅速洞察業務動態&#xff0c;精準…