被誤解的TCP

2021-08-19 12:20:18 字數 1738 閱讀 9091

文:林沛滿

人一旦形成某種思維定勢,就很難再改變了。知道我收到最多的讀者來信是問什麼嗎?「林工,有些tcp包發出去之後沒有看到對應的ack,算不算丟包啊?」這個問題讓我很是好奇,明明rfc上沒有這樣的規定,為什麼總有讀者覺得每乙個資料報都應該有對應的ack呢?後來才注意到,很多提問者是做**開發出身的,已經習慣了每個http請求發出去,就一定會收到乙個http響應(見圖1),因此就把這個模式套到了tcp上。其實不止http,絕大多數應用層協議都採用這種一問一答的工作方式。

圖1tcp當然也可以採用這種方式,但並非必要。就像我們不用每天都跟公司算一次工錢,而是攢到月底結算一樣,資料接收方也可以累積一些包才對傳送方ack一次。至於ack的頻率,不同的作業系統有不同的偏好,比如我實驗室中的linux客戶端喜歡每收到兩個包ack一次,見圖2。

圖2而windows客戶端則懶得多,隔好多個包才ack一次,見圖3的97號包。

圖3這兩種方式都是正常的,但linux對流量更「大手大腳」一點,因為純ack也算流量的。其實在網路頻寬越來越大的今天,人們已經不在乎這種小流量了。不過手機作業系統還是要慎重考慮的,畢竟蜂窩資料是按流量計費的,能省一點是一點。我的安卓手機就是每收到乙個包都會ack的,想到這裡我的心都在滴血。圖4是我在微博上開啟一張美女圖時產生的流量,你看這些密密麻麻的純ack,每個都白費我40位元組的流量。

圖4也許以後會有手機廠商優化它,然後以此作為賣點。如果是從我這本書裡學到的,請為它命名「林朗臺演算法」。

既然接收方不一定收到每個包都要ack,那傳送方怎麼知道哪些包雖然沒有相應的ack,但其實已經送達了呢?記住,ack是有累積效應的,它隱含了「在此之前的其他包也已收到」的意思,比如圖3中第97號包的ack=65701不僅表示收到了96號包(其seq+len=64273+1428=65701),而且暗示之前的其他包也都收到了。因此86~95號包雖然沒有被顯式ack,但傳送方知道它們也已經被送達了。

另乙個對tcp的廣泛誤解則和udp相關。有不少技術人員認為tcp的效率低,因為其傳輸過程中需要往返時間來確認(ack)。而udp無需確認,因此能不停地發包,效率就高了。事實真的如此嗎?這其實是對tcp傳輸機制的嚴重誤解。我們可以假設乙個場景來模擬tcp的工作方式:有大批貨物要從a地運往b地。如果只用一輛貨車來運的話,馬路上就只有一輛車在來回跑(回程相當於tcp的ack包),效率確實很低,對tcp的誤解可能也出自這個原因。但如果在不塞車的前提下盡量增加貨車數量,使整條馬路上充滿車,總傳輸效率就提高了。tcp傳送視窗的意義相當於貨車的數量,只要視窗足夠大,tcp也可以不受往返時間的約束而源源不斷地傳資料。這就是為什麼無論在區域網還是廣域網,tcp還是最受歡迎的傳輸層協議。

當然tcp確實也有因為往返時間而降低效率的時候,比如在傳輸小塊資料的場景。本來能在1個往返時間完成的小事,卻要額外耗費3次握手和4次揮手的開銷,dns查詢就符合這種場景。目前http基本建立在tcp連線上,所以也會因為tcp的三次握手而增加延遲。你可能聽說過google發布的quic(quickudpinternetconnection)協議,它就是為了消除tcp的延遲而設計的代替品。在某些領域可以視為tcp的競爭對手,目前在google的**上已經可以試用了。

被誤解的外鏈判定標準

外鏈,是seo優化中比較重要的組成部分,雖然去年開始綠蘿演算法等搜尋引擎演算法的重制定對於外鏈的影響使得seoer一度質疑外鏈的重要性。但是,筆者小丹認為無論什麼時候好的外鏈永遠可以給 帶來驚喜。之前我們也曾分析過怎樣做外鏈,什麼樣的外鏈才能偶成為有效鏈結。那時候我們就突出乙個重點高質量鏈結,而製作...

《被誤解的C 學習和使用》的案例

假設我們現在有個任務,要做乙個程式,將乙個陣列中的每乙個元素乘上100,然後賦值回去。為此,我寫下了這樣的c int ai new int 10 初始化ai。foreach int i in ai 我又寫了c vectorai 10 初始化ai。for vector iterator i ai.be...

TCP連線被意外重置的原因

今天在做伺服器壓力測試的時候,出現了很奇怪的情況,與伺服器建立連線會成功,但是很快會被重置 reset 掉。花了半天時間,終於找到原因所在,我把過程和結果寫下來與大家分享。伺服器正常邏輯是 接受連線,等待使用者註冊報文,處理其他請求,如果連線一段時間沒有活動,則主動關閉連線。客戶端邏輯是 與伺服器建...