原作者有一個非常棒的個人博客,歡迎圍觀
知音專欄
TCP提供一種面向連接的,可靠的字節(jié)流服務。
TCP首部的數(shù)據(jù)格式如下。(如果不計任選字段,通常是20個字節(jié))
源端口:源端口和IP地址的作用是標識報文的返回地址。
目的端口:端口指明接收方計算機上的應用程序接口。
TCP報頭中的源端口號和目的端口號同IP數(shù)據(jù)報中的源IP與目的IP唯一確定一條TCP連接。
序號:是TCP可靠傳輸?shù)年P鍵部分。序號是該報文段發(fā)送的數(shù)據(jù)組的第一個字節(jié)的序號。在TCP傳送的流中,每一個字節(jié)都有一個序號。比如一個報文段的序號為300,報文段數(shù)據(jù)部分共有100字節(jié),則下一個報文段的序號為400。所以序號確保了TCP傳輸?shù)挠行蛐浴?/span>
確認號:即ACK,指明下一個期待收到的字節(jié)序號,表明該序號之前的所有數(shù)據(jù)已經(jīng)正確無誤的收到。確認號只有當ACK標志為1時才有效。比如建立連接時,SYN報文的ACK標志位為0。
首部長度/數(shù)據(jù)偏移:占4位,它指出TCP報文的數(shù)據(jù)距離TCP報文段的起始處有多遠。由于首部可能含有可選項內(nèi)容,因此TCP報頭的長度是不確定的,報頭不包含任何任選字段則長度為20字節(jié),4位首部長度字段所能表示的最大值為1111,轉化為10進制為15,15*32/8=60,故報頭最大長度為60字節(jié)。首部長度也叫數(shù)據(jù)偏移,是因為首部長度實際上指示了數(shù)據(jù)區(qū)在報文段中的起始偏移值。
保留:占6位,保留今后使用,但目前應都位0。
控制位:URG ACK PSH RST SYN FIN,共6個,每一個標志位表示一個控制功能。
緊急URG:當URG=1,表明緊急指針字段有效。告訴系統(tǒng)此報文段中有緊急數(shù)據(jù)
確認ACK:僅當ACK=1時,確認號字段才有效。TCP規(guī)定,在連接建立后所有報文的傳輸都必須把ACK置1。
推送PSH:當兩個應用進程進行交互式通信時,有時在一端的應用進程希望在鍵入一個命令后立即就能收到對方的響應,這時候就將PSH=1。
復位RST:當RST=1,表明TCP連接中出現(xiàn)嚴重差錯,必須釋放連接,然后再重新建立連接。
同步SYN:在連接建立時用來同步序號。當SYN=1,ACK=0,表明是連接請求報文,若同意連接,則響應報文中應該使SYN=1,ACK=1。
終止FIN:用來釋放連接。當FIN=1,表明此報文的發(fā)送方的數(shù)據(jù)已經(jīng)發(fā)送完畢,并且要求釋放。
窗口:滑動窗口大小,用來告知發(fā)送端接受端的緩存大小,以此控制發(fā)送端發(fā)送數(shù)據(jù)的速率,從而達到流量控制。窗口大小時一個16bit字段,因而窗口大小最大為65535。
校驗和:奇偶校驗,此校驗和是對整個的 TCP 報文段,包括 TCP 頭部和 TCP 數(shù)據(jù),以 16 位字進行計算所得。由發(fā)送端計算和存儲,并由接收端進行驗證。
緊急指針:只有當 URG 標志置 1 時緊急指針才有效。緊急指針是一個正的偏移量,和順序號字段中的值相加表示緊急數(shù)據(jù)最后一個字節(jié)的序號。 TCP 的緊急方式是發(fā)送端向另一端發(fā)送緊急數(shù)據(jù)的一種方式。
選項和填充:最常見的可選字段是最長報文大小,又稱為MSS(Maximum Segment Size),每個連接方通常都在通信的第一個報文段(為建立連接而設置SYN標志為1的那個段)中指明這個選項,它表示本端所能接受的最大報文段的長度。選項長度不一定是32位的整數(shù)倍,所以要加填充位,即在這個字段中加入額外的零,以保證TCP頭是32的整數(shù)倍。
數(shù)據(jù)部分: TCP 報文段中的數(shù)據(jù)部分是可選的。在一個連接建立和一個連接終止時,雙方交換的報文段僅有 TCP 首部。如果一方?jīng)]有數(shù)據(jù)要發(fā)送,也使用沒有任何數(shù)據(jù)的首部來確認收到的數(shù)據(jù)。在處理超時的許多情況中,也會發(fā)送不帶任何數(shù)據(jù)的報文段。
第一次握手:客戶端發(fā)送syn包(syn=x)到服務器,并進入SYN_SEND狀態(tài),等待服務器確認;
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=x+1),同時自己也發(fā)送一個SYN包(syn=y),即SYN+ACK包,此時服務器進入SYN_RECV狀態(tài);
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發(fā)送確認包ACK(ack=y+1),此包發(fā)送完畢,客戶端和服務器進入ESTABLISHED狀態(tài),完成三次握手。
握手過程中傳送的包里不包含數(shù)據(jù),三次握手完畢后,客戶端與服務器才正式開始傳送數(shù)據(jù)。理想狀態(tài)下,TCP連接一旦建立,在通信雙方中的任何一方主動關閉連接之前,TCP 連接都將被一直保持下去。
建立連接的過程是利用客戶服務器模式,假設主機A為客戶端,主機B為服務器端。
采用三次握手是為了防止失效的連接請求報文段突然又傳送到主機B,因而產(chǎn)生錯誤。
失效的連接請求報文段是指:主機A發(fā)出的連接請求沒有收到主機B的確認,于是經(jīng)過一段時間后,主機A又重新向主機B發(fā)送連接請求,且建立成功,順序完成數(shù)據(jù)傳輸??紤]這樣一種特殊情況,主機A第一次發(fā)送的連接請求并沒有丟失,而是因為網(wǎng)絡節(jié)點導致延遲達到主機B,主機B以為是主機A又發(fā)起的新連接,于是主機B同意連接,并向主機A發(fā)回確認,但是此時主機A根本不會理會,主機B就一直在等待主機A發(fā)送數(shù)據(jù),導致主機B的資源浪費。
采用兩次握手不行,原因就是上面說的失效的連接請求的特殊情況。而在三次握手中, client和server都有一個發(fā)syn和收ack的過程, 雙方都是發(fā)后能收, 表明通信則準備工作OK。
為什么不是四次握手呢? 大家應該知道通信中著名的藍軍紅軍約定, 這個例子說明, 通信不可能100%可靠, 而上面的三次握手已經(jīng)做好了通信的準備工作, 再增加握手, 并不能顯著提高可靠性, 而且也沒有必要。
數(shù)據(jù)傳輸完畢后,雙方都可釋放連接。最開始的時候,客戶端和服務器都是處于ESTABLISHED狀態(tài),假設客戶端主動關閉,服務器被動關閉。
第一次揮手:客戶端發(fā)送一個FIN,用來關閉客戶端到服務器的數(shù)據(jù)傳送,也就是客戶端告訴服務器:我已經(jīng)不 會再給你發(fā)數(shù)據(jù)了(當然,在fin包之前發(fā)送出去的數(shù)據(jù),如果沒有收到對應的ack確認報文,客戶端依然會重發(fā)這些數(shù)據(jù)),但是,此時客戶端還可 以接受數(shù)據(jù)。
FIN=1,其序列號為seq=u(等于前面已經(jīng)傳送過來的數(shù)據(jù)的最后一個字節(jié)的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態(tài)。 TCP規(guī)定,F(xiàn)IN報文段即使不攜帶數(shù)據(jù),也要消耗一個序號。
第二次揮手:服務器收到FIN包后,發(fā)送一個ACK給對方并且?guī)献约旱男蛄刑杝eq,確認序號為收到序號+1(與SYN相同,一個FIN占用一個序號)。此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態(tài)。TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處于半關閉狀態(tài),即客戶端已經(jīng)沒有數(shù)據(jù)要發(fā)送了,但是服務器若發(fā)送數(shù)據(jù),客戶端依然要接受。這個狀態(tài)還要持續(xù)一段時間,也就是整個CLOSE-WAIT狀態(tài)持續(xù)的時間。
此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態(tài),等待服務器發(fā)送連接釋放報文(在這之前還需要接受服務器發(fā)送的最后的數(shù)據(jù))。
第三次揮手:服務器發(fā)送一個FIN,用來關閉服務器到客戶端的數(shù)據(jù)傳送,也就是告訴客戶端,我的數(shù)據(jù)也發(fā)送完了,不會再給你發(fā)數(shù)據(jù)了。由于在半關閉狀態(tài),服務器很可能又發(fā)送了一些數(shù)據(jù),假定此時的序列號為seq=w,此時,服務器就進入了LAST-ACK(最后確認)狀態(tài),等待客戶端的確認。
第四次揮手:主動關閉方收到FIN后,發(fā)送一個ACK給被動關閉方,確認序號為收到序號+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態(tài)。注意此時TCP連接還沒有釋放,必須經(jīng)過2?MSL(最長報文段壽命)的時間后,當客戶端撤銷相應的TCB后,才進入CLOSED狀態(tài)。
服務器只要收到了客戶端發(fā)出的確認,立即進入CLOSED狀態(tài)。同樣,撤銷TCB后,就結束了這次的TCP連接??梢钥吹剑掌鹘Y束TCP連接的時間要比客戶端早一些。至此,完成四次揮手。
MSL(Maximum Segment Lifetime),TCP允許不同的實現(xiàn)可以設置不同的MSL值。
第一,保證客戶端發(fā)送的最后一個ACK報文能夠到達服務器,因為這個ACK報文可能丟失,站在服務器的角度看來,我已經(jīng)發(fā)送了FIN+ACK報文請求斷開了,客戶端還沒有給我回應,應該是我發(fā)送的請求斷開報文它沒有收到,于是服務器又會重新發(fā)送一次,而客戶端就能在這個2MSL時間段內(nèi)收到這個重傳的報文,接著給出回應報文,并且會重啟2MSL計時器。
第二,防止類似與“三次握手”中提到了的“已經(jīng)失效的連接請求報文段”出現(xiàn)在本連接中。客戶端發(fā)送完最后一個確認報文后,在這個2MSL時間中,就可以使本連接持續(xù)的時間內(nèi)所產(chǎn)生的所有報文段都從網(wǎng)絡中消失。這樣新的連接中不會出現(xiàn)舊連接的請求報文。
建立連接的時候, 服務器在LISTEN狀態(tài)下,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發(fā)送給客戶端。
而關閉連接時,服務器收到對方的FIN報文時,僅僅表示對方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),而自己也未必全部數(shù)據(jù)都發(fā)送給對方了,所以己方可以立即關閉,也可以發(fā)送一些數(shù)據(jù)給對方后,再發(fā)送FIN報文給對方來表示同意現(xiàn)在關閉連接,因此,己方ACK和FIN一般都會分開發(fā)送,從而導致多了一次。
聯(lián)系客服