Nagle 算法、ACK 延遲和 Rlogin 回顯
我正在閱讀有關 TCP 數據流、延遲 ACK和Nagle’s Algorithm 的資訊。
到目前為止,我明白:
- TCP 上的延遲 ACK實現會在接收到的段的確認上產生延遲,以使應用程序有機會在確認的同時寫入一些數據,從而避免發送空 ACK 數據包並導致網路擁塞。
- Nagle 的算法實現聲明您不能發送一個小的 TCP 段,而另一個小段仍然未被確認。這避免了流量被載入了幾個tinygram。
在某些互動式應用程序上,例如 Rlogin,Nagle 的算法和延遲 ACK可能會“衝突”:
當我們鍵入鍵盤輸入時,Rlogin 會將鍵盤輸入發送到伺服器,並且某些鍵(如F1)會生成一個以上的字節(F1 = Escape + 左括號 + M)。如果這些字節被一一傳送到 TCP,它們可以在不同的段中發送。
伺服器在獲得整個序列之前不會回復回顯,因此所有 ACK 都會被延遲(期望來自應用程序的一些數據)。另一方面,客戶端會在發送下一個字節之前等待第一個字節確認(尊重Nagle 算法)。這種組合最終導致“滯後”的 Rlogin。
tcpdump
在 Rlogin 上發送的F1和F2鍵如下所示:type Fl key 1 0.0 slip.1023 > vangogh. login: P 1:2(1) ack 2 2 0.250520 (0.2505) vangogh.login > slip.1023: P 2:4(2) ack 2 3 0.251709 (0.0012) slip.1023 > vangogh.login: P 2:4(2) ack 4 4 0.490344 (0.2386) vangogh.login > slip.1023: P 4:6(2) ack 4 5 0.588694 (0.0984) slip.1023 > vangogh.login: . ack 6 type F2 key 6 2.836830 (2.2481) slip.1023 > vangogh.login: P 4:5(1) ack 6 7 3.132388 (0.2956) vangogh.login > slip.1023: P 6:8(2) ack 5 8 3.133573 (0.0012) slip.1023 > vangogh.login: P 5:7(2) ack 8 9 3.370346 (0.2368) vangogh.login > slip.1023: P 8:10(2) ack 7 10 3.388692 (0.0183) slip.1023 > vangogh.login: . ack 10
現在的疑問:即使我閱讀的頁面表明伺服器在擁有整個密鑰序列之前沒有回復回顯,但通過擷取的數據包
tcpdump
顯示密鑰正在各自的 ACK 上回顯(第一個回復是 2字節長,因為ESC的回顯是兩個字元 - 插入符號 + 左括號)。如果數據正在從應用程序發送到 TCP(回顯響應),為什麼 ACK 會延遲?根據所陳述的,關於伺服器在回顯之前等待完整序列,ACK 不應該不包含直到最後一個 ACK 的回顯,這將包含整個序列回顯?
參考: http: //people.na.infn.it/~garufi/didattica/CorsoAcq/Trasp/Lezione9/tcpip_ill/tcp_int.htm
您說 rlogin “伺服器在完成整個序列之前不會回復回顯”,例如通常
^[OP
的 F1 鍵。但這只是一個沒有根據的假設。還有一個錯誤的。而您的 tcpdump 實驗表明情況並非如此;它準確地顯示了一個滯後的 rlogin 實現,沒有任何這樣的“優化”。實際上,伺服器的正常預期行為是立即回顯任何輸入。如果客戶端出於某種原因決定
^[
單獨發送,則此後不會出現奇怪的延遲((完全不考慮 TCP)。對於laggy-rlogin 類問題應該是一個乾淨的解決方案,即對話的每一方(**客戶端和伺服器)只有
send()
當他們真誠地相信此時有人正在等待顯示結果時。在這種約束下,發送是客戶端的一個主要錯誤^[
,當軟體已經知道這^[OP
是完整的預期序列並且人類使用者對完整結果感興趣,而不僅僅是^[
(人類決定發送OP
還是也許OQ
是回應,還是什麼?)。因此,對於軟體開發人員的違反直覺的建議,無論他們與 TCP 的業務是什麼,或者他們開發客戶端還是伺服器端:記住這
send()
不是立即的,它可能會延遲你的下一次傳輸,所以更小心地使用它(結果Nagle 增加了延遲,延遲 ACK 增加了更多延遲)。