參考文章:https://www.2cto.com/net/201209/157585.html
tcp狀態(tài):
LISTEN:偵聽來自遠方的TCP端口的連接請求
SYN-SENT:再發(fā)送連接請求后等待匹配的連接請求
SYN-RECEIVED:再收到和發(fā)送一個連接請求后等待對方對連接請求的確認
ESTABLISHED:代表一個打開的連接
FIN-WAIT-1:等待遠程TCP連接中斷請求,或先前的連接中斷請求的確認
FIN-WAIT-2:從遠程TCP等待連接中斷請求
CLOSE-WAIT:等待從本地用戶發(fā)來的連接中斷請求
CLOSING:等待遠程TCP對連接中斷的確認
LAST-ACK:等待原來的發(fā)向遠程TCP的連接中斷請求的確認TIME-WAIT:等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認
CLOSED:沒有任何連接狀態(tài)

image

image

image

image

image
- TCP是一個面向連接的協(xié)議,所以在連接雙方發(fā)送數(shù)據(jù)之前,都需要首先建立一條連接。這和前面講到的協(xié)議完全不同。前面講的所有協(xié)議都只是發(fā)送數(shù)據(jù)而已,大多數(shù)都不關心發(fā)送的數(shù)據(jù)是不是送到,UDP尤其明顯,從編程的角度來說,UDP編程也要簡單的多----UDP都不用考慮數(shù)據(jù)分片。書中用telnet登陸退出來解釋TCP協(xié)議連接的建立和中止的過程,可以看到,TCP連接的建立可以簡單的稱為三次握手,而連接的中止則可以叫做四次握手。
- 1.連接的建立在建立連接的時候,客戶端首先向服務器申請打開某一個端口(用SYN段等于1的TCP報文),然后服務器端發(fā)回一個ACK報文通知客戶端請求報文收到,客戶端收到確認報文以后再次發(fā)出確認報文確認剛才服務器端發(fā)出的確認報文(繞口么),至此,連接的建立完成。這就叫做三次握手。如果打算讓雙方都做好準備的話,一定要發(fā)送三次報文,而且只需要三次報文就可以了??梢韵胍?,如果再加上TCP的超時重傳機制,那么TCP就完全可以保證一個數(shù)據(jù)包被送到目的地。
- 2.結(jié)束連接TCP有一個特別的概念叫做half-close,這個概念是說,TCP的連接是全雙工(可以同時發(fā)送和接收)連接,因此在關閉連接的時候,必須關閉傳和送兩個方向上的連接??蛻魴C給服務器一個FIN為1的TCP報文,然后服務器返回給客戶端一個確認ACK報文,并且發(fā)送一個FIN報文,當客戶機回復ACK報文后(四次握手),連接就結(jié)束了。
- 3.最大報文長度在建立連接的時候,通信的雙方要互相確認對方的最大報文長度(MSS),以便通信。一般這個SYN長度是MTU減去固定IP首部和TCP首部長度。對于一個以太網(wǎng),一般可以達到1460字節(jié)。當然如果對于非本地的IP,這個MSS可能就只有536字節(jié),而且,如果中間的傳輸網(wǎng)絡的MSS更佳的小的話,這個值還會變得更小。
- 4.TCP的狀態(tài)遷移圖書P182頁給出了TCP的狀態(tài)圖,這是一個看起來比較復雜的狀態(tài)遷移圖,因為它包含了兩個部分---服務器的狀態(tài)遷移和客戶端的狀態(tài)遷移,如果從某一個角度出發(fā)來看這個圖,就會清晰許多,這里面的服務器和客戶端都不是絕對的,發(fā)送數(shù)據(jù)的就是客戶端,接受數(shù)據(jù)的就是服務器。
- 4.1.客戶端應用程序的狀態(tài)遷移圖客戶端的狀態(tài)可以用如下的流程來表示:CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED以上流程是在程序正常的情況下應該有的流程,從書中的圖中可以看到,在建立連接時,當客戶端收到SYN報文的ACK以后,客戶端就打開了數(shù)據(jù)交互地連接。而結(jié)束連接則通常是客戶端主動結(jié)束的,客戶端結(jié)束應用程序以后,需要經(jīng)歷FIN_WAIT_1,F(xiàn)IN_WAIT_2等狀態(tài),這些狀態(tài)的遷移就是前面提到的結(jié)束連接的四次握手。
- 4.2.服務器的狀態(tài)遷移圖服務器的狀態(tài)可以用如下的流程來表示:CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED在建立連接的時候,服務器端是在第三次握手之后才進入數(shù)據(jù)交互狀態(tài),而關閉連接則是在關閉連接的第二次握手以后(注意不是第四次)。而關閉以后還要等待客戶端給出最后的ACK包才能進入初始的狀態(tài)。
- 4.3.其他狀態(tài)遷移書中的圖還有一些其他的狀態(tài)遷移,這些狀態(tài)遷移針對服務器和客戶端兩方面的總結(jié)如下LISTEN->SYN_SENT,對于這個解釋就很簡單了,服務器有時候也要打開連接的嘛。SYN_SENT->SYN收到,服務器和客戶端在SYN_SENT狀態(tài)下如果收到SYN數(shù)據(jù)報,則都需要發(fā)送SYN的ACK數(shù)據(jù)報并把自己的狀態(tài)調(diào)整到SYN收到狀態(tài),準備進入ESTABLISHEDSYN_SENT->CLOSED,在發(fā)送超時的情況下,會返回到CLOSED狀態(tài)。SYN_收到->LISTEN,如果受到RST包,會返回到LISTEN狀態(tài)。SYN_收到->FIN_WAIT_1,這個遷移是說,可以不用到ESTABLISHED狀態(tài),而可以直接跳轉(zhuǎn)到FIN_WAIT_1狀態(tài)并等待關閉。
- 4.4.2MSL等待狀態(tài)書中給的圖里面,有一個TIME_WAIT等待狀態(tài),這個狀態(tài)又叫做2MSL狀態(tài),說的是在TIME_WAIT2發(fā)送了最后一個ACK數(shù)據(jù)報以后,要進入TIME_WAIT狀態(tài),這個狀態(tài)是防止最后一次握手的數(shù)據(jù)報沒有傳送到對方那里而準備的(注意這不是四次握手,這是第四次握手的保險狀態(tài))。這個狀態(tài)在很大程度上保證了雙方都可以正常結(jié)束,但是,問題也來了。由于插口的2MSL狀態(tài)(插口是IP和端口對的意思,socket),使得應用程序在2MSL時間內(nèi)是無法再次使用同一個插口的,對于客戶程序還好一些,但是對于服務程序,例如httpd,它總是要使用同一個端口來進行服務,而在2MSL時間內(nèi),啟動httpd就會出現(xiàn)錯誤(插口被使用)。為了避免這個錯誤,服務器給出了一個平靜時間的概念,這是說在2MSL時間內(nèi),雖然可以重新啟動服務器,但是這個服務器還是要平靜的等待2MSL時間的過去才能進行下一次連接。
- 4.5.FIN_WAIT_2狀態(tài)這就是著名的半關閉的狀態(tài)了,這是在關閉連接時,客戶端和服務器兩次握手之后的狀態(tài)。在這個狀態(tài)下,應用程序還有接受數(shù)據(jù)的能力,但是已經(jīng)無法發(fā)送數(shù)據(jù),但是也有一種可能是,客戶端一直處于FIN_WAIT_2狀態(tài),而服務器則一直處于WAIT_CLOSE狀態(tài),而直到應用層來決定關閉這個狀態(tài)。
- 5.RST,同時打開和同時關閉RST是另一種關閉連接的方式,應用程序應該可以判斷RST包的真實性,即是否為異常中止。而同時打開和同時關閉則是兩種特殊的TCP狀態(tài),發(fā)生的概率很小。
- 6.TCP服務器設計前面曾經(jīng)講述過UDP的服務器設計,可以發(fā)現(xiàn)UDP的服務器完全不需要所謂的并發(fā)機制,它只要建立一個數(shù)據(jù)輸入隊列就可以。但是TCP不同,TCP服務器對于每一個連接都需要建立一個獨立的進程(或者是輕量級的,線程),來保證對話的獨立性。所以TCP服務器是并發(fā)的。而且TCP還需要配備一個呼入連接請求隊列(UDP服務器也同樣不需要),來為每一個連接請求建立對話進程,這也就是為什么各種TCP服務器都有一個最大連接數(shù)的原因。而根據(jù)源主機的IP和端口號碼,服務器可以很輕松的區(qū)別出不同的會話,來進行數(shù)據(jù)的分發(fā)。