傳輸控制協(xié)議(TCP,Transmission Control Protocol)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,由IETF的RFC 793 [1] 定義。
TCP旨在適應(yīng)支持多網(wǎng)絡(luò)應(yīng)用的分層協(xié)議層次結(jié)構(gòu)。 連接到不同但互連的計(jì)算機(jī)通信網(wǎng)絡(luò)的主計(jì)算機(jī)中的成對進(jìn)程之間依靠TCP提供可靠的通信服務(wù)。TCP假設(shè)它可以從較低級(jí)別的協(xié)議獲得簡單的,可能不可靠的數(shù)據(jù)報(bào)服務(wù)。 原則上,TCP應(yīng)該能夠在從硬線連接到分組交換或電路交換網(wǎng)絡(luò)的各種通信系統(tǒng)之上操作。
字段 | 長度 | 含義 |
---|---|---|
Source Port | 16比特 | 源端口,標(biāo)識(shí)哪個(gè)應(yīng)用程序發(fā)送。 |
Destination Port | 16比特 | 目的端口,標(biāo)識(shí)哪個(gè)應(yīng)用程序接收。 |
Sequence Number | 32比特 | 序號(hào)字段。TCP鏈接中傳輸?shù)臄?shù)據(jù)流中每個(gè)字節(jié)都編上一個(gè)序號(hào)。序號(hào)字段的值指的是本報(bào)文段所發(fā)送的數(shù)據(jù)的第一個(gè)字節(jié)的序號(hào)。 |
Acknowledgment Number | 32比特 | 確認(rèn)號(hào),是期望收到對方的下一個(gè)報(bào)文段的數(shù)據(jù)的第1個(gè)字節(jié)的序號(hào),即上次已成功接收到的數(shù)據(jù)字節(jié)序號(hào)加1。只有ACK標(biāo)識(shí)為1,此字段有效。 |
Data Offset | 4比特 | 數(shù)據(jù)偏移,即首部長度,指出TCP報(bào)文段的數(shù)據(jù)起始處距離TCP報(bào)文段的起始處有多遠(yuǎn),以32比特(4字節(jié))為計(jì)算單位。最多有60字節(jié)的首部,若無選項(xiàng)字段,正常為20字節(jié)。 |
Reserved | 6比特 | 保留,必須填0。 |
URG | 1比特 | 緊急指針有效標(biāo)識(shí)。它告訴系統(tǒng)此報(bào)文段中有緊急數(shù)據(jù),應(yīng)盡快傳送(相當(dāng)于高優(yōu)先級(jí)的數(shù)據(jù))。 |
ACK | 1比特 | 確認(rèn)序號(hào)有效標(biāo)識(shí)。只有當(dāng)ACK=1時(shí)確認(rèn)號(hào)字段才有效。當(dāng)ACK=0時(shí),確認(rèn)號(hào)無效。 |
PSH | 1比特 | 標(biāo)識(shí)接收方應(yīng)該盡快將這個(gè)報(bào)文段交給應(yīng)用層。接收到PSH = 1的TCP報(bào)文段,應(yīng)盡快的交付接收應(yīng)用進(jìn)程,而不再等待整個(gè)緩存都填滿了后再向上交付。 |
RST | 1比特 | 重建連接標(biāo)識(shí)。當(dāng)RST=1時(shí),表明TCP連接中出現(xiàn)嚴(yán)重錯(cuò)誤(如由于主機(jī)崩潰或其他原因),必須釋放連接,然后再重新建立連接。 |
SYN | 1比特 | 同步序號(hào)標(biāo)識(shí),用來發(fā)起一個(gè)連接。SYN=1表示這是一個(gè)連接請求或連接接受請求。 |
FIN | 1比特 | 發(fā)端完成發(fā)送任務(wù)標(biāo)識(shí)。用來釋放一個(gè)連接。FIN=1表明此報(bào)文段的發(fā)送端的數(shù)據(jù)已經(jīng)發(fā)送完畢,并要求釋放連接。 |
Window | 16比特 | 窗口:TCP的流量控制,窗口起始于確認(rèn)序號(hào)字段指明的值,這個(gè)值是接收端正期望接收的字節(jié)數(shù)。窗口最大為65535字節(jié)。 |
Checksum | 16比特 | 校驗(yàn)字段,包括TCP首部和TCP數(shù)據(jù),是一個(gè)強(qiáng)制性的字段,一定是由發(fā)端計(jì)算和存儲(chǔ),并由收端進(jìn)行驗(yàn)證。在計(jì)算檢驗(yàn)和時(shí),要在TCP報(bào)文段的前面加上12字節(jié)的偽首部。 |
Urgent Pointer | 16比特 | 緊急指針,只有當(dāng)URG標(biāo)志置1時(shí)緊急指針才有效。TCP的緊急方式是發(fā)送端向另一端發(fā)送緊急數(shù)據(jù)的一種方式。緊急指針指出在本報(bào)文段中緊急數(shù)據(jù)共有多少個(gè)字節(jié)(緊急數(shù)據(jù)放在本報(bào)文段數(shù)據(jù)的最前面)。 |
Options | 可變 | 選項(xiàng)字段。TCP協(xié)議最初只規(guī)定了一種選項(xiàng),即最長報(bào)文段長度(數(shù)據(jù)字段加上TCP首部),又稱為MSS。MSS告訴對方TCP“我的緩存所能接收的報(bào)文段的數(shù)據(jù)字段的最大長度是MSS個(gè)字節(jié)”。 |
Padding | 可變 | 填充字段,用來補(bǔ)位,使整個(gè)首部長度是4字節(jié)的整數(shù)倍。 |
data | 可變 | TCP負(fù)載。 |
SYN(synchronous建立聯(lián)機(jī)) ACK(acknowledgement 確認(rèn)) PSH(push傳送) FIN(finish結(jié)束) RST(reset重置) URG(urgent緊急)
所謂的三次握手即TCP連接的建立。這個(gè)連接必須是一方主動(dòng)打開,另一方被動(dòng)打開的。以下為客戶端主動(dòng)發(fā)起連接的圖解:
握手之前主動(dòng)打開連接的客戶端結(jié)束CLOSED階段,被動(dòng)打開的服務(wù)器端也結(jié)束CLOSED階段,并進(jìn)入LISTEN階段。隨后開始“三次握手”:
(1)首先客戶端向服務(wù)器端發(fā)送一段TCP報(bào)文,其中: 標(biāo)記位為SYN,表示“請求建立新連接”; 序號(hào)為Seq=X(X一般為1); 隨后客戶端進(jìn)入SYN-SENT階段。
(2)服務(wù)器端接收到來自客戶端的TCP報(bào)文之后,結(jié)束LISTEN階段。并返回一段TCP報(bào)文,其中: 標(biāo)志位為SYN和ACK,表示“確認(rèn)客戶端的報(bào)文Seq序號(hào)有效,服務(wù)器能正常接收客戶端發(fā)送的數(shù)據(jù),并同意創(chuàng)建新連接”(即告訴客戶端,服務(wù)器收到了你的數(shù)據(jù)); 序號(hào)為Seq=y; 確認(rèn)號(hào)為Ack=x+1,表示收到客戶端的序號(hào)Seq并將其值加1作為自己確認(rèn)號(hào)Ack的值;隨后服務(wù)器端進(jìn)入SYN-RCVD階段。
(3)客戶端接收到來自服務(wù)器端的確認(rèn)收到數(shù)據(jù)的TCP報(bào)文之后,明確了從客戶端到服務(wù)器的數(shù)據(jù)傳輸是正常的,結(jié)束SYN-SENT階段。并返回最后一段TCP報(bào)文。其中: 標(biāo)志位為ACK,表示“確認(rèn)收到服務(wù)器端同意連接的信號(hào)”(即告訴服務(wù)器,我知道你收到我發(fā)的數(shù)據(jù)了); 序號(hào)為Seq=x+1,表示收到服務(wù)器端的確認(rèn)號(hào)Ack,并將其值作為自己的序號(hào)值; 確認(rèn)號(hào)為Ack=y+1,表示收到服務(wù)器端序號(hào)Seq,并將其值加1作為自己的確認(rèn)號(hào)Ack的值; 隨后客戶端進(jìn)入ESTABLISHED階段。 服務(wù)器收到來自客戶端的“確認(rèn)收到服務(wù)器數(shù)據(jù)”的TCP報(bào)文之后,明確了從服務(wù)器到客戶端的數(shù)據(jù)傳輸是正常的。結(jié)束SYN-SENT階段,進(jìn)入ESTABLISHED階段。 在客戶端與服務(wù)器端傳輸?shù)腡CP報(bào)文中,雙方的確認(rèn)號(hào)Ack和序號(hào)Seq的值,都是在彼此Ack和Seq值的基礎(chǔ)上進(jìn)行計(jì)算的,這樣做保證了TCP報(bào)文傳輸?shù)倪B貫性。一旦出現(xiàn)某一方發(fā)出的TCP報(bào)文丟失,便無法繼續(xù)"握手",以此確保了"三次握手"的順利完成。 此后客戶端和服務(wù)器端進(jìn)行正常的數(shù)據(jù)傳輸。這就是“三次握手”的過程。
所謂的四次揮手即TCP連接的釋放(解除)。連接的釋放必須是一方主動(dòng)釋放,另一方被動(dòng)釋放。以下為客戶端主動(dòng)發(fā)起釋放連接的圖解:
揮手之前主動(dòng)釋放連接的客戶端結(jié)束ESTABLISHED階段。隨后開始“四次揮手”: (1)首先客戶端想要釋放連接,向服務(wù)器端發(fā)送一段TCP報(bào)文,其中: 標(biāo)記位為FIN,表示“請求釋放連接“; 序號(hào)為Seq=U; 隨后客戶端進(jìn)入FIN-WAIT-1階段,即半關(guān)閉階段。并且停止在客戶端到服務(wù)器端方向上發(fā)送數(shù)據(jù),但是客戶端仍然能接收從服務(wù)器端傳輸過來的數(shù)據(jù)。 注意:這里不發(fā)送的是正常連接時(shí)傳輸?shù)臄?shù)據(jù)(非確認(rèn)報(bào)文),而不是一切數(shù)據(jù),所以客戶端仍然能發(fā)送ACK確認(rèn)報(bào)文。
(2)服務(wù)器端接收到從客戶端發(fā)出的TCP報(bào)文之后,確認(rèn)了客戶端想要釋放連接,隨后服務(wù)器端結(jié)束ESTABLISHED階段,進(jìn)入CLOSE-WAIT階段(半關(guān)閉狀態(tài))并返回一段TCP報(bào)文,其中: 標(biāo)記位為ACK,表示“接收到客戶端發(fā)送的釋放連接的請求”; 序號(hào)為Seq=V; 確認(rèn)號(hào)為Ack=U+1,表示是在收到客戶端報(bào)文的基礎(chǔ)上,將其序號(hào)Seq值加1作為本段報(bào)文確認(rèn)號(hào)Ack的值; 隨后服務(wù)器端開始準(zhǔn)備釋放服務(wù)器端到客戶端方向上的連接。 客戶端收到從服務(wù)器端發(fā)出的TCP報(bào)文之后,確認(rèn)了服務(wù)器收到了客戶端發(fā)出的釋放連接請求,隨后客戶端結(jié)束FIN-WAIT-1階段,進(jìn)入FIN-WAIT-2階段 前"兩次揮手"既讓服務(wù)器端知道了客戶端想要釋放連接,也讓客戶端知道了服務(wù)器端了解了自己想要釋放連接的請求。于是,可以確認(rèn)關(guān)閉客戶端到服務(wù)器端方向上的連接了。
(3)服務(wù)器端自從發(fā)出ACK確認(rèn)報(bào)文之后,經(jīng)過CLOSED-WAIT階段,做好了釋放服務(wù)器端到客戶端方向上的連接準(zhǔn)備,再次向客戶端發(fā)出一段TCP報(bào)文,其中: 標(biāo)記位為FIN,ACK,表示“已經(jīng)準(zhǔn)備好釋放連接了”。注意:這里的ACK并不是確認(rèn)收到服務(wù)器端報(bào)文的確認(rèn)報(bào)文。 序號(hào)為Seq=W; 確認(rèn)號(hào)為Ack=U+1;表示是在收到客戶端報(bào)文的基礎(chǔ)上,將其序號(hào)Seq值加1作為本段報(bào)文確認(rèn)號(hào)Ack的值。 隨后服務(wù)器端結(jié)束CLOSE-WAIT階段,進(jìn)入LAST-ACK階段。并且停止在服務(wù)器端到客戶端的方向上發(fā)送數(shù)據(jù),但是服務(wù)器端仍然能夠接收從客戶端傳輸過來的數(shù)據(jù)。
(4)客戶端收到從服務(wù)器端發(fā)出的TCP報(bào)文,確認(rèn)了服務(wù)器端已做好釋放連接的準(zhǔn)備,結(jié)束FIN-WAIT-2階段,進(jìn)入TIME-WAIT階段,并向服務(wù)器端發(fā)送一段報(bào)文,其中: 標(biāo)記位為ACK,表示“接收到服務(wù)器準(zhǔn)備好釋放連接的信號(hào)”。 序號(hào)為Seq=U+1;表示是在收到了服務(wù)器端報(bào)文的基礎(chǔ)上,將其確認(rèn)號(hào)Ack值作為本段報(bào)文序號(hào)的值。 確認(rèn)號(hào)為Ack=W+1;表示是在收到了服務(wù)器端報(bào)文的基礎(chǔ)上,將其序號(hào)Seq值作為本段報(bào)文確認(rèn)號(hào)的值。 隨后客戶端開始在TIME-WAIT階段等待2MSL 為什么要客戶端要等待2MSL呢?見后文。
服務(wù)器端收到從客戶端發(fā)出的TCP報(bào)文之后結(jié)束LAST-ACK階段,進(jìn)入CLOSED階段。由此正式確認(rèn)關(guān)閉服務(wù)器端到客戶端方向上的連接。 客戶端等待完2MSL之后,結(jié)束TIME-WAIT階段,進(jìn)入CLOSED階段,由此完成“四次揮手”。
后“兩次揮手”既讓客戶端知道了服務(wù)器端準(zhǔn)備好釋放連接了,也讓服務(wù)器端知道了客戶端了解了自己準(zhǔn)備好釋放連接了。于是,可以確認(rèn)關(guān)閉服務(wù)器端到客戶端方向上的連接了,由此完成“四次揮手”。 與“三次揮手”一樣,在客戶端與服務(wù)器端傳輸?shù)腡CP報(bào)文中,雙方的確認(rèn)號(hào)Ack和序號(hào)Seq的值,都是在彼此Ack和Seq值的基礎(chǔ)上進(jìn)行計(jì)算的,這樣做保證了TCP報(bào)文傳輸?shù)倪B貫性,一旦出現(xiàn)某一方發(fā)出的TCP報(bào)文丟失,便無法繼續(xù)"揮手",以此確保了"四次揮手"的順利完成。
這是因?yàn)榉?wù)端的LISTEN狀態(tài)下的SOCKET當(dāng)收到SYN報(bào)文的建連請求后,它可以把ACK和SYN(ACK起應(yīng)答作用,而SYN起同步作用)放在 一個(gè)報(bào)文里來發(fā)送。
但關(guān)閉連接時(shí),當(dāng)收到對方的FIN報(bào)文通知時(shí),它僅僅表示對方?jīng)]有數(shù)據(jù)發(fā)送給你了;但未必你所有的數(shù)據(jù)都全部發(fā)送給對方了,所以你可以 未必會(huì)馬上會(huì)關(guān)閉SOCKET,也即你可能還需要發(fā)送一些數(shù)據(jù)給對方之后,再發(fā)送FIN報(bào)文給對方來表示你同意現(xiàn)在可以關(guān)閉連接了,所以它這里的ACK報(bào) 文和FIN報(bào)文多數(shù)情況下都是分開發(fā)送的.
因?yàn)殡m然雙方都同意關(guān)閉連接了,而且握手的4個(gè)報(bào)文也都協(xié)調(diào)和發(fā)送完畢,按理可以直接回到CLOSED狀態(tài)(就好比從SYN_SEND狀態(tài)到ESTABLISH狀態(tài)那樣);但是我們認(rèn)為網(wǎng)絡(luò)是不可靠的,你無法保證你最后發(fā)送的ACK報(bào)文會(huì)一定被對方收到,因此對方處于LAST_ACK狀態(tài)下的SOCKET可能會(huì)因?yàn)槌瑫r(shí)未收到ACK報(bào)文,而重發(fā)FIN報(bào)文,所以這個(gè)TIME_WAIT狀態(tài)的作用就是用來重發(fā)可能丟失的ACK報(bào)文。
原因:對于基于TCP的HTTP協(xié)議,關(guān)閉TCP連接的是Server端,這樣,Server端回進(jìn)入TIME_WAIT狀態(tài),可想而知,對于訪問量大的Web Server,會(huì)存在大量的TIME_WAIT狀態(tài)。
解決辦法:
?。?)開啟socket重用,允許TIME_WAIT的socket重新用于TCP連接
?。?)開啟快速回收
在三次握手過程中,Server發(fā)送SYN-ACK之后,收到Client的ACK之前的TCP連接稱為半連接(half-open connect),此時(shí)Server處于SYN_RCVD狀態(tài),當(dāng)收到ACK后,Server轉(zhuǎn)入ESTABLISHED狀態(tài)。SYN攻擊就是Client在短時(shí)間內(nèi)偽造大量不存在的IP地址,并向Server不斷地發(fā)送SYN包,Server回復(fù)確認(rèn)包,并等待Client的確認(rèn),由于源地址是不存在的,因此,Server需要不斷重發(fā)直至超時(shí),這些偽造的SYN包將產(chǎn)時(shí)間占用未連接隊(duì)列,導(dǎo)致正常的SYN請求因?yàn)殛?duì)列滿而被丟棄,從而引起網(wǎng)絡(luò)堵塞甚至系統(tǒng)癱瘓。SYN攻擊時(shí)一種典型的DDOS攻擊,檢測SYN攻擊的方式非常簡單,即當(dāng)Server上有大量半連接狀態(tài)且源IP地址是隨機(jī)的,則可以斷定遭到SYN攻擊了,使用如下命令可以讓之現(xiàn)行:
netstat -nap | grep SYN_RECV
更多建議: