天天看點

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

TCP -- Transmission Control Protocol

  • 可靠性
  • TCP報頭
  • 确認應答(ACK)機制
  • 逾時重傳
  • 連接配接管理機制
    • TCP狀态轉移圖
    • 三次握手
    • 四次揮手
      • TIME_WAIT狀态
  • 流量控制
  • 擁塞控制
  • TCP細節優化
    • 快重傳
    • 延遲應答
    • 捎帶應答
  • 面向位元組流
  • TCP異常情況

TCP協定和UDP協定是運作在傳輸層的協定,也是為了結局程序間通信的問題,它相對于UDP協定而言,是一種有連接配接的,可靠的協定。

可靠性

為什麼需要可靠性?

因為網絡的不可靠,而應用層很多時候需要可靠的傳輸(核心)

什麼是可靠性?

  • 盡可能的吧資料發送給對方,不丢包
  • 如果實在發送不到,至少通知應用層這個錯誤
  • 保證資料的有序到達
  • TCP保證不會收的錯誤的資料(隻能保證無意識的錯誤,不能防範有意識的篡改)

TCP報頭

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

确認應答(ACK)機制

簡單了解,可以了解為TCP發送的資料是有編号的,當接收方收到資料後,有責任進行應答,将期待下一次收到的資料的第一個編号發送回來

例:

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

TCP(Segment)既可以當發送使用,也可以當應答使用,互相不沖突

标志位上的ACK就是含有應答的意義(==1是應答,==0不是應答,ASN無效)

逾時重傳

如果長時間未收到應答,可能發生什麼?

  • 資料包可能丢了,對方沒有收到。
  • 對方應答了,但應答包丢失

如果超過一定的時間,仍未收到對應應答,則将對應的資料重新進行發送

如果是應答包丢失的情況下,再次發送資料過去,接收方是否可以判斷?

可以,TCP内部管理着接收資料的序号,TCP段帶有序号

接下來,接收端會将資料丢棄,然後發送應答

如果逾時重傳後還是沒有收到應答怎麼辦?

多次嘗試(有限次數)

1、多次嘗試(retry)過程中,逾時時間往往越來越長

2、當多次嘗試不成功,達到一定門檻值時,就會停止發送,同時還會發一個Segment的充值連結,同時通知應用層,(java中會收到一個異常——SocketException:reset by remote peer)

資料編号 + 确認應答 + 逾時重傳 可以使得資料有序

連接配接管理機制

為什麼需要建立連接配接?至少能證明對方是線上的。

在正常情況下,TCP都要經過三次握手建立連接配接,四次揮手斷開連接配接

有了連接配接管理後,就隻能一對一通信了,沒辦法廣播了。

TCP狀态轉移圖

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

三次握手

SYN是用作TCP段同步的意義

首先由主動連接配接方發起一個 SYN,别連接配接方收到會回複一個ACK,然後被連接配接方也會發送一個SYN,連接配接方收到回複ACK

如圖:

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

也可以了解為:

第一次握手: A給B打電話說,你可以聽到我說話嗎?

第二次握手: B收到了A的資訊,然後對A說: 我可以聽得到你說話啊,你能聽得到我說話嗎?

第三次握手: A收到了B的資訊,然後說可以的,我要給你發資訊啦!

 在三次握手之後,A和B都能确定這麼一件事: 我說的話,你能聽到; 你說的話,我也能聽到。 這樣,就可以開始正常通信了。

 如果兩次,那麼B無法确定B的資訊A是否能收到,是以如果B先說話,可能後面的A都收不到,會出現問題 。

 如果四次,那麼就造成了浪費,因為在三次結束之後,就已經可以保證A可以給B發資訊,A可以收到B的資訊; B可以給A發資訊,B可以收到A的資訊。

四次揮手

當需要釋放連接配接的時候,至少由一方主動發起,

主動關閉方發送FIN,被關閉方發送ACK,被關閉方發送FIN,主動關閉方發送ACK

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

為什麼不可以三次揮手呢?

關閉連接配接時,當收到對方的FIN封包通知時,它僅僅表示對方沒有資料發送給你了;但未必你所有的資料都全部發送給對方了

是以你未必會馬上關閉SOCKET,也即你可能還需要發送一些資料給對方之後,再發送FIN封包給對方來表示你同意現在可以關閉連接配接了,是以它這裡的ACK封包和FIN封包多數情況下都是分開發送的。

可能有人會有疑問,tcp我握手的時候為何ACK(确認)和SYN(建立連接配接)是一起發送。揮手的時候為什麼是分開的時候發送呢?

因為當Server端收到Client端的SYN連接配接請求封包後,可以直接發送SYN+ACK封包。其中ACK封包是用來應答的,SYN封包是用來同步的。

但是關閉連接配接時,當Server端收到FIN封包時,很可能并不會立即關閉 SOCKET,是以隻能先回複一個ACK封包,告訴Client端,“你發的FIN封包我收到了”。隻有等到我Server端所有的封包都發送完了,我才能發送FIN封包,是以不能一起發送。故需要四步揮手。

簡單了解四次揮手:

A:“喂,我不說了 (FIN)。”A->FIN_WAIT1

B:“我知道了(ACK)。等下,上一句還沒說完。Balabala……(傳輸資料)”B->CLOSE_WAIT | A->FIN_WAIT2

B:”好了,說完了,我也不說了(FIN)。”B->LAST_ACK

A:”我知道了(ACK)。”A->TIME_WAIT | B->CLOSED

A等待2MSL,保證B收到了消息,否則重說一次”我知道了”,A->CLOSED

這樣,通過四次揮手,可以把該說的話都說完,并且A和B都知道自己沒話說了,對方也沒花說了,然後就挂掉電話(斷開連結)了 。

TIME_WAIT狀态

TIME_WAIT這個狀态出現在主動關閉方,并且持續時間是2 *MSL(Maximum Segment Live)

出現的原因:

  • 最後一個ACK可能會丢失,是以需要保持一段時間
  • 把停止使用的五元組閑置一段時間,保證網絡上這條連接配接的資料全部失效,小機率可能性這個五元組又重新配置設定了,也保證收到資料一定是新連接配接
  • 2 * MSL的時間,可以保證 : 對方大機率收到了我們的ACK,網絡上所有老連接配接的包已經失效了,即使五元組在配置設定,也安全了。

作為開發人員,發現伺服器上出現了大量的TIME_WAIT,是不是合理的呢?對伺服器有沒有影響?如果有影響怎麼調增代碼結構?

理論上說是合理的。

會有一些影響,連接配接對象一直存在,關于對象關聯下的一系列資源都需要保留(記憶體)

解決方法:避免我們主動關閉連結

CLOSE_WAIT狀态。是被關閉方的狀态

一般而言,對于伺服器上出現大量的CLOSE_WAIT,原因是伺服器沒有正确的關閉socket導緻四次揮手沒有正确的完成,隻需要加上對應的close解決問題。

流量控制

根據接收方的接受能力進行發送量控制

接收視窗:接收方告訴發送方自己目前的接收能力

發送視窗:控制發送量

滑動視窗:控制發送量過程中的過程、動作

在TCP首部的視窗大小的字段通過ACK機制通知發送端,

在TCP發送緩沖區:

例如:

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

擁塞控制

根據網絡擁塞視窗推斷出發送量的大小

根據丢包情況,反推網絡擁塞情況

初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況
初識TCP可靠性TCP報頭确認應答(ACK)機制逾時重傳連接配接管理機制流量控制擁塞控制TCP細節優化面向位元組流TCP異常情況

發送量控制 流量控制 + 擁塞控制

TCP細節優化

快重傳

資料包不停地向接收方發送(不必等到收到ACK在發送下一個),接收方傳遞會ACK應答。如果有一個包丢了,那麼應答ACK會一直發送下一個應該發送的位元組頭,當到達一定次數,發送方會重新發送,丢掉的包,收到後傳回下一個應該發送的位元組頭。

延遲應答

可以每N個包應答一次,超過最大的延遲時間就應答一次

捎帶應答

非sync包,理論上都可以捎帶應答

在延遲應答的基礎上我們發現每次發送都是 一發一收,我怕,我們的ACK可以搭順風車。

面向位元組流

TCP逾時重傳機制 + 發送量控制帶來的副作用是:資料隻能通過位元組流的形式提供給對方

TCP有自己的發送緩沖區和接收緩沖區。

我們要在UDP協定上開發一個可靠的應用層協定,具體怎麼做?

具有TCP的特性:

校驗和、序列号、确認應答、逾時重發、連接配接管理、流量控制、擁塞控制

TCP異常情況

1、程序終止:程序終止會釋放檔案描述符,仍然可以發送FIN,和正常關閉一樣

2、機器重新開機:和程序終止一樣

機器掉電/網線斷開:接收端認為連接配接還在,一旦接收端有寫入操作,接收端發現連接配接不在了,就會進行reset,TCP自己也内置了一個保活定時器,會定期詢問對方是否還在,如果不在也會釋放。

  • 隻要os有機會介入,os就有能力,将所有的連接配接進行四次揮手
  • 如果是os沒有機會介入的關機,主機B上的程序、連接配接都沒有了
  • 如果處于寫資料(發送資料)的狀态,當到達充實門檻值時,會判斷為連接配接已關閉(異常關閉),通知應用層,SocketException,需要一定時間,不能立即可知
  • 如果處于讀資料的狀态——确實無法判定

    解決問題思路:

    1、TCP協定層面有一種KeepAlive機制(每隔一段時間,嘗試發送個空資料)

    2、應用層方法:read(timeout),如果逾時了,嘗試寫一個資料過去——>心跳包(heartbeat)

繼續閱讀