關於Nagle演算法和粘包問題

2022-06-25 01:36:07 字數 2455 閱讀 8227

​ tcp/ip協議中,無論傳送多少資料,總是要在資料前面加上協議頭,同時,對方接收到資料,也需要傳送ack表示確認。為了盡可能的利用網路頻寬,tcp總是希望盡可能的傳送足夠大的資料。(乙個連線會設定mss引數,因此,tcp/ip希望每次都能夠以mss尺寸的資料塊來傳送資料)。nagle演算法就是為了盡可能傳送大塊資料,避免網路中充斥著許多小資料塊,提高網路的利用率。

nagle演算法的基本定義是任意時刻,最多只能有乙個未被確認的小段。 所謂「小段」,指的是小於mss尺寸的資料塊,所謂「未被確認」,是指乙個資料塊傳送出去後,沒有收到對方傳送的ack確認該資料已收到。

nagle演算法的規則:

(1)如果包長度達到mss,則允許傳送;

(2)如果該包含有fin,則允許傳送;

(3)設定了tcp_nodelay選項,則允許傳送;

(4)未設定tcp_cork選項時,若所有發出去的小資料報(包長度小於mss)均被確認,則允許傳送;

(5)上述條件都未滿足,但發生了超時(一般為200ms),則立即傳送。

nagle演算法只允許乙個未被ack的包存在於網路,它並不管包的大小,因此它事實上就是乙個擴充套件的停止等待協議,只不過它是基於包停-等的,而不是基於位元組停-等的。nagle演算法完全由tcp協議的ack機制決定,這會帶來一些問題,比如如果對端ack回覆很快的話,nagle事實上不會拼接太多的資料報,雖然避免了網路擁塞,網路總體的利用率依然很低,所以nagle演算法一般和延遲確認機制一起使用。但是網上也有說法說,同時使用nagle和延遲確認在一些情況下可能會導致相互等待到超時的情況。

考慮關閉nagle的情況

對端不向本端傳送資料,並且對延時比較敏感的操作;這種操作沒法捎帶ack;

寫-寫-讀操作;對於此種情況,優先使用其他方式,而不是關閉nagle演算法:

--使用writev,而不是兩次呼叫write,單個writev呼叫會使tcp輸出一次而不是兩次,只產生乙個tcp分節,這是首選方法;

--把兩次寫操作的資料複製到單個緩衝區,然後對緩衝區呼叫一次write;

--關閉nagle演算法,呼叫write兩次;有損於網路,通常不考慮;

ack機制

​ 在tcp協議種,接收方成功收到資料後,會回覆乙個ack資料報,用於表示已經收到了ack確認號以前的所有資料。如果傳送方在一定時間內沒有收到接受方的ack確認包,就會重新傳送資料報。ack機制和序列號,訊息重傳機制一起保證了tcp協議的可靠性。

​ 當接受方收到資料報時,可能因為下面的一些原因,不會立即返回ack確認:

收到的資料報的序列號前還有未收到的資料。

ack的值在到達最大時,會重新從零開始。

為了降低流量,而引入的延遲確認機制。

ack延遲確認機制

​ 接收方在收到資料後,並不會立即回覆ack,而是延遲一定時間。一般ack延遲傳送的時間為200ms,但這個200ms並非收到資料後需要延遲的時間。系統有乙個固定的定時器每隔200ms會來檢查是否需要傳送ack包。這樣做有兩個目的。

1、這樣做的目的是ack是可以合併的,也就是指如果連續收到兩個tcp包,並不一定需要ack兩次,只要回覆最終的ack就可以了,可以降低網路流量。

2、如果接收方有資料要傳送,那麼就會在傳送資料的tcp資料報裡,帶上ack資訊。這樣做,可以避免大量的ack以乙個單獨的tcp包傳送,減少了網路流量。

ack延遲確認和nagle演算法混用可能出現的問題

比較典型的場合就是寫-寫-讀,即通過多個寫小片資料向對端傳送單個邏輯的操作,兩次寫資料長度小於mss,當第一次寫資料到達對端後,對端延遲ack,不傳送ack,而本端因為要傳送的資料長度小於mss,所以nagle演算法起作用,資料並不會立即傳送,而是等待對端傳送的第一次資料確認ack;這樣的情況下,需要等待對端超時傳送ack,然後本段才能傳送第二次寫的資料,從而造成延遲;

什麼是粘包

​ 因為tcp是面向位元組流的協議,沒有訊息保護邊界,同時在tcp的首部沒有表示資料長度的字段。一方傳送的多個資料報,可能會被合併成乙個大的資料報進行傳輸,這就是粘包。粘包情況有兩種,一種是粘在一起的包都是完整的資料報,另一種情況是粘在一起的包有不完整的包。

​ 與粘包對應的還有乙個概率:分包是指在出現粘包的時候我們的接收方要進行分包處理。(在長連線中都會出現) 資料報的邊界發生錯位,導致讀出錯誤的資料分包,進而曲解原始資料含義。

粘包的成因

粘包的解決方法

​ 粘包問題的本質就是無法區分資料報的邊界,只要解決了這個問題,也就解決了粘包問題。

1、傳送端給每個資料報新增包首部,首部中應該至少包含資料報的長度,這樣接收端在接收到資料後,通過讀取包首部的長度字段,便知道每乙個資料報的實際長度了。

2、傳送端將每個資料報封裝為固定長度(不夠的可以通過補0填充),這樣接收端每次從接收緩衝區中讀取固定長度的資料就自然而然的把每個資料報拆分開來。

3、可以在資料報之間設定邊界,如新增特殊符號,這樣,接收端通過這個邊界就可以將不同的資料報拆分開。

TCP粘包, UDP丟包, nagle演算法

一 tcp粘包 1.什麼時候考慮粘包 如果利用tcp每次傳送資料,就與對方建立連線,然後雙方傳送完一段資料後,就關閉連線,這樣就不會出現粘包問題 因為只有一種包結構,類似於http協議,udp不會出現粘包現象 關閉連線主要要雙方都傳送close連線 參考tcp關閉協議 如 a需要傳送一段字串給b,那...

20200923 關於tcp的粘包問題

只有tcp有粘包現象,udp永遠不會粘包,因為tcp是面向位元組流,而udp是面向資料報的協議。傳送端可能是1k1k的傳送資料,接收端可能是2k2k的提取資料,當然也有可能3k或者6k的提取資料,或者一次只提取幾個位元組的資料。應用程式看到的資料是乙個整體,是乙個流 stream 一條訊息有多少位元...

nagle演算法和TCP NODELAY

寫socket發現的乙個詭異現象,當時將多個小資料寫操作合併成乙個寫操作,問題就沒了。chenshuo同學還建議我設定tcp nodelay,只是後來因為事情忙,也就沒有再深究下去。現在大概明白,是由於nagle演算法在搗亂。tcp ip協議中,無論傳送多少資料,總是要在資料前面加上協議頭,同時,對...