在網(wǎng)絡(luò)協(xié)議棧中褐隆, 目前只有tcp提供了一種面向連接的可靠性數(shù)據(jù)傳輸污它。 而可靠性庶弃,無非就是保證轨蛤,我發(fā)給你的,你一定要收到虫埂。確保中間的通信過程中祥山,不會丟失數(shù)據(jù)和亂序〉舴 在TCP保證可靠性數(shù)據(jù)傳輸?shù)膶崿F(xiàn)來看缝呕, 超時重傳澳窑、序列號及數(shù)據(jù)的應(yīng)答 這三個特征 就是實現(xiàn)可靠性的最基本保證,而對于tcp窗口大小等等設(shè)置供常,也是保證可靠性的一個方面摊聋。所有的目的只為一個,保證傳輸數(shù)據(jù)的完整性栈暇。 為了解決傳輸線路的不穩(wěn)定性造成數(shù)據(jù)包的丟失情況麻裁,tcp 使用了發(fā)送方超時重傳和接收方數(shù)據(jù)應(yīng)答的策略。概括而言源祈,就是一種“狀態(tài)協(xié)議“煎源,保證通信雙方數(shù)據(jù)收發(fā)的一致性。
tcp協(xié)議
源端口:表明發(fā)送端所使用的端口號香缺,用于目標(biāo)主機回應(yīng)手销。
目的端口:表明要連接的目標(biāo)主機的端口號。
序號:
表明發(fā)送的數(shù)據(jù)包的順序图张,一般為上次發(fā)送包中的順序號+1锋拖。
若該數(shù)據(jù)包是整個TCP連接中的第一個包(SYN包),則該值是隨機生成的祸轮。
確認(rèn)號:
表明本端TCP已經(jīng)接收到的數(shù)據(jù)兽埃,其值表示期待對端發(fā)送的下一個字節(jié)的序號。
實際上告訴對方适袜,在這個序號減1以前的字節(jié)已正確接收讲仰。
若該數(shù)據(jù)包是整個TCP連接中的第一個包(SYN包),則確認(rèn)號一般為0痪蝇。
數(shù)據(jù)偏移:
表示以32位(4字節(jié))為單位的TCP分組頭的總長度(首部長度)鄙陡,用于確定用戶數(shù)據(jù)區(qū)的起始位置。
在沒有可變內(nèi)容的情況下躏啰,TCP頭部的大小為20字節(jié)趁矾,對應(yīng)該值為5。
標(biāo)志位:
緊急標(biāo)志位(URG):開啟時表明此數(shù)據(jù)包處于緊急狀態(tài)應(yīng)該優(yōu)先處理
確認(rèn)標(biāo)志位(ACK):開啟時表明確認(rèn)號有效给僵,否則忽略確認(rèn)號
推送標(biāo)志位(PSH):開啟時表明應(yīng)該盡快交付給應(yīng)用進程毫捣,而不必等到緩存區(qū)填滿才推送,比如 telnet 的場景
復(fù)位標(biāo)志位(RST):開啟時表明TCP連接出現(xiàn)連接出現(xiàn)錯誤帝际,數(shù)據(jù)包非法拒絕連接
同步標(biāo)志位(SYN):開啟時表明連接建立的標(biāo)志
終止標(biāo)志位(FIN):開啟時表明釋放一個連接
窗口大新:表明期望接受到的數(shù)據(jù)包字節(jié)數(shù),用于擁塞控制蹲诀。
校驗和:實現(xiàn)對TCP報文頭以及數(shù)據(jù)區(qū)進行校驗斑粱。
緊急指針:在緊急狀態(tài)下(URG打開),指出窗口中緊急數(shù)據(jù)的位置(末端)脯爪。
選項(可變):用于支持一些特殊的變量则北,比如最大分組長度(MSS)矿微。
填充:用于保證可變選項為32 bit的整數(shù)倍。
備注:一般情況下TCP 頭部為20字節(jié)尚揣,加上20字節(jié)的 IP頭部涌矢,一個數(shù)據(jù)包至少包含40字節(jié)的頭部
tcp狀態(tài)機
下面簡析一下 TCP的各個狀態(tài)。
TCP_CLOSE:關(guān)閉狀態(tài)快骗, 一個新建的TCP socket 會處于該狀態(tài)娜庇。
TCP_LISTEN: 監(jiān)聽狀態(tài),一般服務(wù)器端套接字在調(diào)用Listen系統(tǒng)調(diào)用后即處于該狀態(tài)方篮。
TCP_SYN_SENT:同步信號已經(jīng)發(fā)送狀態(tài)名秀,這個狀態(tài)一般是指客戶端發(fā)送SYN(建立連接的同步)數(shù)據(jù)包后所處的狀態(tài)(tcp三次握手的第一個包)。在接收到遠(yuǎn)端服務(wù)器端的應(yīng)答后恭取,即從該狀態(tài)進入TCP_ESTABLISHED狀態(tài)泰偿。
TCP_SYN_RECEIVED:同步信號已經(jīng)接受狀態(tài)熄守,服務(wù)器端在接受到遠(yuǎn)端客戶端SYN數(shù)據(jù)包后蜈垮,進行相應(yīng)的處理(創(chuàng)建通信套接字等),然后發(fā)送應(yīng)答數(shù)據(jù)包(tcp三次握手的第二個包)裕照,并將新創(chuàng)建的通信套接字狀態(tài)設(shè)置為TCP_SYN_RECEIVED攒发,在接受到客戶端的應(yīng)答后,即進入TCP_ESTABLISED狀態(tài)晋南。
TCP_ESTABLISED:建立連接狀態(tài)惠猿,這是雙方進行正常通信所處的狀態(tài)。
TCP_FIN_WAIT_1:本地發(fā)送FIN(用于結(jié)束連接的)數(shù)據(jù)包后即可進入該狀態(tài)负间,等待對方的應(yīng)答偶妖。一般一端發(fā)送完其所要發(fā)送的數(shù)據(jù)后,即可發(fā)送FIN數(shù)據(jù)包政溃,此時發(fā)送通道被關(guān)閉趾访,但仍可繼續(xù)接受遠(yuǎn)端發(fā)送的數(shù)據(jù)包。在接受到遠(yuǎn)端發(fā)送的對于FIN數(shù)據(jù)包的應(yīng)答后董虱,將進入TCP_FIN_WAIT_2狀態(tài)扼鞋。
TCP_FIN_WAIT_2:進入該狀態(tài)表示本地已經(jīng)接受到遠(yuǎn)端發(fā)送的對于本地之前發(fā)送的FIN數(shù)據(jù)包的應(yīng)答。進入該狀態(tài)后愤诱,本地仍然可以繼續(xù)接受遠(yuǎn)端發(fā)送給本地的數(shù)據(jù)包云头。在接受到遠(yuǎn)端發(fā)送的FIN數(shù)據(jù)包后(表示遠(yuǎn)端也已經(jīng)發(fā)送完數(shù)據(jù)),本地將發(fā)送一個應(yīng)答數(shù)據(jù)包淫半,并進入TCP_TIME_WAIT狀態(tài)溃槐。TCP_TIME_WAIT狀態(tài)存在的時間被稱為2MSL時間,這一方面是為避免本地發(fā)送的應(yīng)答數(shù)據(jù)包丟失科吭,另一方面避免一個新創(chuàng)建的套接字接收到舊套接字中遺留的數(shù)據(jù)包竿痰。
TCP_TIME_WAIT:該轉(zhuǎn)狀態(tài)唄稱為2MSL等待狀態(tài)脆粥。如果在此期間接收到遠(yuǎn)端發(fā)送的FIN數(shù)據(jù)包,則表示之前在TCP_FIN_WAIT_2狀態(tài)發(fā)送的ACK應(yīng)答數(shù)據(jù)包在傳輸中丟失或者長時間被延遲影涉,從而造成了遠(yuǎn)端重新發(fā)送了FIN數(shù)據(jù)包变隔,此時重復(fù)ACK應(yīng)答數(shù)據(jù)包。一旦2MSL時間到期蟹倾,則將進入TCP_CLOSED狀態(tài)匣缘,即完成關(guān)閉操作。
TCP_CLOSE_WAIT:該狀態(tài)存在于后關(guān)閉的一端鲜棠。當(dāng)接收到遠(yuǎn)端發(fā)送的FIN數(shù)據(jù)包后肌厨,本地發(fā)送一個ACK應(yīng)答數(shù)據(jù)包,并將該套接字狀態(tài)從TCP_ESTABLISED設(shè)置為TCP_CLOSE_WAIT豁陆。本地可以繼續(xù)向遠(yuǎn)端發(fā)送數(shù)據(jù)包柑爸,在發(fā)送完所有的數(shù)據(jù)后,本地將發(fā)送一個FIN數(shù)據(jù)包關(guān)閉本地發(fā)送通道盒音,并將狀態(tài)設(shè)置為TCP_LAST_ACK狀態(tài)表鳍,等待遠(yuǎn)端對FIN數(shù)據(jù)包的應(yīng)答數(shù)據(jù)包。
TCP_CLOSING:如果通信雙方同時發(fā)送FIN數(shù)據(jù)包祥诽,則同時進行關(guān)閉操作譬圣,則雙方將同時進入TCP_CLOSING狀態(tài)。具體的雄坪,本地發(fā)送一個FIN數(shù)據(jù)包以結(jié)束本地數(shù)據(jù)包發(fā)送厘熟,如果在等待應(yīng)答期間,接收到遠(yuǎn)端發(fā)送的FIN數(shù)據(jù)包维哈,則本地將狀態(tài)設(shè)置為TCP_CLOSING狀態(tài)绳姨。在接收到應(yīng)答后,再繼續(xù)裝入到TCP_CLOSE_WAIT狀態(tài)阔挠。
TCP_LAST_ACK:作為后關(guān)閉的一方飘庄,在發(fā)送FIN數(shù)據(jù)包后,即進入TCP_LAST_ACK狀態(tài)谒亦。此時等待遠(yuǎn)端發(fā)送應(yīng)答數(shù)據(jù)包竭宰,在接收到應(yīng)答數(shù)據(jù)包后,即完成關(guān)閉操作份招,進入TCP_CLOSE狀態(tài)切揭。
關(guān)于tcp中time_wait狀態(tài)的4個問題
1.time_wait狀態(tài)是什么
簡單來說:time_wait狀態(tài)是四次揮手中server向client發(fā)送FIN終止連接后進入的狀態(tài)。下圖為tcp四次揮手過程
能夠看到time_wait狀態(tài)存在于client收到serverFin并返回ack包時的狀態(tài)
當(dāng)處于time_wait狀態(tài)時锁摔,我們無法創(chuàng)建新的連接廓旬,由于port被占用。
2.為什么會有time_wait狀態(tài)
time_wait存在的原因有兩點
1.可靠的終止TCP連接。
可靠的終止TCP連接孕豹,若處于time_wait的client發(fā)送給server確認(rèn)報文段丟失的話涩盾,server將在此又一次發(fā)送FIN報文段,那么client必須處于一個可接收的狀態(tài)就是time_wait而不是close狀態(tài)励背。
2.保證讓遲來的TCP報文段有足夠的時間被識別并丟棄春霍。
保證遲來的TCP報文段有足夠的時間被識別并丟棄,linux 中一個TCPport不能打開兩次或兩次以上叶眉。當(dāng)client處于time_wait狀態(tài)時我們將無法使用此port建立新連接址儒,假設(shè)不存在time_wait狀態(tài),新連接可能會收到舊連接的數(shù)據(jù)衅疙。
time_wait持續(xù)的時間是2MSL莲趣,保證舊的數(shù)據(jù)能夠丟棄。由于網(wǎng)絡(luò)中的數(shù)據(jù)最大存在MSL(maxinum segment lifetime)
3.哪一方會有time_wait狀態(tài)
time_wait狀態(tài)是一般有client的狀態(tài)饱溢。 并且會占用port喧伞,有時產(chǎn)生在server端,由于server主動斷開連接或者發(fā)生異常
4.怎樣避免time_wait狀態(tài)占用資源
假設(shè)是client绩郎,我們一般不用操心潘鲫,由于client一般選用暫時port。再次創(chuàng)建連接會新分配一個port嗽上。
除非指定client使用某port次舌,只是一般不須要這么做熄攘。
假設(shè)是server主動關(guān)閉連接后異常終止兽愤。則由于它總是使用用一個知名serverport號,所以連接的time_wait狀態(tài)將導(dǎo)致它不能重新啟動挪圾。只是我們能夠通過socket的選項SO_REUSEADDR來強制進程馬上使用處于time_wait狀態(tài)的連接占用的port浅萧。
通過socksetopt設(shè)置后,即使sock處于time_wait狀態(tài)哲思,與之綁定的socket地址也能夠馬上被重用洼畅。
此外也能夠通過改動內(nèi)核參數(shù)/proc/sys/net/ipv4/tcp_tw/recycle來高速回收被關(guān)閉的socket,從而是tcp連接根本不進入time_wait狀態(tài),進而同意應(yīng)用程序馬上重用本地的socket地址棚赔。
tcp攻擊
所謂SYN 洪泛攻擊帝簇,就是利用SYNACK 報文的時候,服務(wù)器會為客戶端請求分配緩存靠益,那么黑客(攻擊者)丧肴,就可以使用一批虛假的ip向服務(wù)器大量地發(fā)建立TCP 連接的請求,服務(wù)器為這些虛假ip分配了緩存后胧后,處在SYN_RCVD狀態(tài)芋浮,存放在半連接隊列中;另外壳快,服務(wù)器發(fā)送的請求又不可能得到回復(fù)(ip都是假的纸巷,能回復(fù)就有鬼了)镇草,只能不斷地重發(fā)請求,直到達(dá)到設(shè)定的時間/次數(shù)后瘤旨,才會關(guān)閉梯啤。
服務(wù)器不斷為這些半開連接分配資源(但從未使用),導(dǎo)致服務(wù)器的連接資源被消耗殆盡存哲,不過所幸条辟,我們可以使用SYN Cookie進行有效地防御。
所謂的SYN Cookie防御系統(tǒng)宏胯,與前面接收到SYN 報文就分配緩存不同羽嫡,此時暫不分配資源;同時利用SYN 報文的源和目的地IP和端口肩袍,以及服務(wù)器存儲的一個秘密數(shù)杭棵,使用它們進行散列,得到server_isn氛赐,然后附著在SYNACK 報文中發(fā)送給客戶端魂爪,接下來就是對ACK 報文進行判斷,如果其返回的ack字段正好等于server_isn + 1艰管,說明這是一個合法的ACK滓侍,那么服務(wù)器才會為其生成一個具有套接字的全開的連接。