TCP三次握手與四次揮手及Socket編寫

TCP三次握手與四次揮手及Socket編寫

http://www.360doc.com/content/12/1204/10/9220372_252012979.shtml

https://www.cnblogs.com/tomato0906/articles/4696932.html

1.三次握手原理:

TCP握手協議

在TCP/IP協議中,TCP協議提供可靠的連接服務,採用三次握手建立一個連接。

第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認; (客戶端問服務器:你愛我嗎?)

第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;(服務器回答:我愛你,你也愛我嗎?)

第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。 (客戶端回答:我愛你,你也愛我,那我們結婚吧!(ESTABLISHED))

完成三次握手,客戶端與服務器開始傳送數據,在上述過程中,還有一些重要的概念:

未連接隊列:在三次握手協議中,服務器維護一個未連接隊列,該隊列爲每個客戶端的SYN包(syn=j)開設一個條目,該條目表明服務器已收到SYN包,並向客戶發出確認,正在等待客戶的確認包。這些條目所標識的連接在服務器處於Syn_RECV狀態,當服務器收到客戶的確認包時,刪除該條目,服務器進入ESTABLISHED狀態。
Backlog參數:表示未連接隊列的最大容納數目。

SYN-ACK 重傳次數 服務器發送完SYN-ACK包,如果未收到客戶確認包,服務器進行首次重傳,等待一段時間仍未收到客戶確認包,進行第二次重傳,如果重傳次數超過系統規定的最大重傳次數,系統將該連接信息從半連接隊列中刪除。注意,每次重傳等待的時間不一定相同。

半連接存活時間:是指半連接隊列的條目存活的最長時間,也即服務從收到SYN包到確認這個報文無效的最長時間,該時間值是所有重傳請求包的最長等待時間總和。有時我們也稱半連接存活時間爲Timeout時間、SYN_RECV存活時間。

2.四次揮手原理:

TCP的終止通過雙方的四次握手實現。發起終止的一方執行主動關閉,響應的另一方執行被動關閉。

  1. 發起方(client)更改狀態爲FIN_WAIT_1,關閉應用程序進程,發出一個TCP的FIN段;
  2. 接收方收到FIN段,返回一個帶確認序號的ACK,同時向自己對應的進程發送一個文件結束符EOF,同時更改狀態爲CLOSE_WAIT(server),發起方接到ACK後狀態更改爲FIN_WAIT_2(client);
  3. 接收方關閉應用程序進程,更改狀態爲LAST_ACK(server),並向對方發出一個TCP的FIN段;
  4. 發起方接到FIN後狀態更改爲TIME_WAIT(client),併發出這個FIN的ACK確認。ACK發送成功後(2MSL內)雙方TCP狀態變爲CLOSED。

我們不難看出上面的顯示的結果的意思。根據TCP協議,主動發起關閉的一方,會進入TIME_WAIT狀態(TCP實現必須可靠地終止連接的兩個方向(全雙工關閉)),持續2*MSL(Max Segment Lifetime),缺省爲240秒.

第一次揮手:客戶端A發送一個FIN,用來關閉客戶A到服務器B的數據傳送;
第二次揮手:服務器B收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1,和SYN一樣,一個FIN將佔用一個序號;
第三次揮手:服務器B關閉與客戶端A的連接,發送一個FIN給客戶端A;
第四次揮手:客戶端A發回ACK報文確認,並將確認序號設置爲收到序號加1;

客戶端主動關閉
Client------------------------------ Server
FIN_WAIT_1 -----fin m-------> CLOSE_WAIT(被動關閉)
FIN_WAIT_2 <–ack m+1-----
TIME_WAIT <------fin n------- LAST_ACK
----ack n+1 ---------------------> CLOSED

簡單的說就是
客戶端對服務器說:我不愛你了,咱們離婚吧!--------------->(FIN_WAIT_1狀態,等待迴應)
服務器說:那離婚吧,把你的東西都拿走! --------------->(FIN_WAIT_2狀態,在關閉連接前將最後一點數據傳完)
服務器又說:咱們來個Kiss Goodbye吧! --------------->(LAST_ACK,關閉連接,並請求最後一次確認)
客戶端迴應:波兒~ --------------> (CLOSED,完畢)

#################################################################################

以下問題來自網絡
1.爲什麼建立連接協議是三次握手,而關閉連接卻是四次握手呢?
這是因爲服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文裏來發送。但關閉連接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你所有的數據都全部發送給對方了,所以你未必會馬上會關閉SOCKET,即你可能還需要發送一些數據給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉連接了,所以它這裏的ACK報文和FIN報文多數情況下都是分開發送的。

2.爲什麼TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?

注:MSL(最大分段生存期)指明TCP報文在Internet上最長生存時間,每個具體的TCP實現都必須選擇一個確定的MSL值。RFC 1122建議是2分鐘,但BSD傳統實現採用了30秒。TIME_WAIT 狀態最大保持時間是2 * MSL,也就是1-4分鐘。

TIME_WAIT的等待時間爲2MSL,即最大段生存時間.如果 TIME_WAIT 狀態保持時間不足夠長(比如小於2MSL),第一個連接就正常終止了。第二個擁有相同相關五元組的連接出現(因爲連接終止前發起的一方可能需要重發 ACK,所以停留在該狀態的時間必須爲MSL的2倍。),而第一個連接的重複報文到達,干擾了第二個連接。TCP實現必須防止某個連接的重複報文在連接終止後出現,所以讓TIME_WAIT態保持時間足夠長(2MSL),連接相應方向上的TCP報文要麼完全響應完畢,要麼被丟棄。建立第二個連接的時候,不會混淆。

注:MSL(最大分段生存期)指明TCP報文在Internet上最長生存時間,每個具體的TCP實現都必須選擇一個確定的MSL值。RFC 1122建議是2分鐘,但BSD傳統實現採用了30秒。TIME_WAIT 狀態最大保持時間是2 * MSL,也就是1-4分鐘。

這是因爲雖然雙方都同意關閉連接了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到 ESTABLISH狀態那樣);但是因爲我們必須要假想網絡是不可靠的,你無法保證你最後發送的ACK報文會一定被對方收到,因此對方處於 LAST_ACK狀態下的SOCKET可能會因爲超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的 ACK報文。

3.SYN攻擊

實例:
攻擊主機C(地址僞裝後爲C’)-----大量SYN包---->被攻擊主機
C’<-------SYN/ACK包----被攻擊主機

由於C’地址不可達,被攻擊主機等待SYN包超時。攻擊主機通過發大量SYN包填滿未連接隊列,導致正常SYN包被拒絕服務。另外,SYN洪水攻擊還可以通過發大量ACK包進行DoS攻擊。

from:http://blog.chinaunix.net/uid-20665441-id-305439.html

如何編寫Socket套接字?(程序員面試寶典)

答案:服務器端程序編寫:

(1) 調用ServerSocket(int port)創建一個服務器套接字,並綁定到指定端口上。

(2) 調用accept(),監聽連接請求,接收連接,返回通信套接字。

(3) 調用Socket類的getOutStream()和getInputStream獲取輸出流和輸入流,開始網絡數據的發送和接收。

(4) 關閉通信套接字Socket.close( )。

客戶端程序編寫:

(1)調用Socket()創建一個流套接字,並連接到服務器端。

(2)調用Socket類的getOutStream()和getInputStream獲取輸出流和輸入流,開始網絡數據的發送和接收。

(3)關閉通信套接字Socket.close( )。

Socket套接字程序編寫步驟

服務器端程序的編寫步驟:

第一步:調用socket()函數創建一個用於通信的套接字。

第二步:給已經創建的套接字綁定一個端口號,這一般通過設置網絡套接口地址和調用bind()函數來實現。

第三步:調用listen()函數使套接字成爲一個監聽套接字。

第四步:調用accept()函數來接受客戶端的連接,這是就可以和客戶端通信了。

第五步:處理客戶端的連接請求。

第六步:終止連接。


客戶端程序編寫步驟:

第一步:調用socket()函數創建一個用於通信的套接字。

第二步:通過設置套接字地址結構,說明客戶端與之通信的服務器的IP地址和端口號。

第三步:調用connect()函數來建立與服務器的連接。

第四步:調用讀寫函數發送或者接收數據。

第五步:終止連接。
form:http://blog.163.com/shufeng1911@126/blog/static/29948685201062952533184/


**CLOSED**: 這個沒什麼好說的了,表示初始狀態。

LISTEN: 這個也是非常容易理解的一個狀態,表示服務器端的某個SOCKET處於監聽狀態,可以接受連接了。

SYN_RCVD: 這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是服務器端的SOCKET在建立TCP連接時的三次握手會話過程中的一箇中間狀態,很短暫,基本 上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程序,故意將三次TCP握手過程中最後一個ACK報文不予發送。因此這種狀態 時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。

SYN_SENT: 這個狀態與SYN_RCVD遙想呼應,當客戶端SOCKET執行CONNECT連接時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀 態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。

ESTABLISHED:這個容易理解了,表示連接已經建立了。

FIN_WAIT_1: 這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別 是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連接,向對方發送了FIN報文,此時該SOCKET即 進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬 上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。

FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點數據需要傳送給你,稍後再關閉連接。

TIME_WAIT: 表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶 FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。

CLOSING: 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你發送FIN報文後,按理來說是應該先收到(或同時收到)對方的 ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什 麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方幾乎在同時close一個SOCKET的話,那麼就出現了雙方同時發送FIN報 文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連接。

CLOSE_WAIT: 這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後發送FIN報文給自己,你係統毫無疑問地會迴應一個ACK報文給對 方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有數據發送給對方,如果沒有的話,那麼你也就可以 close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。

LAST_ACK: 這個狀態還是比較容易好理解的,它是被動關閉一方在發送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。

轉載自:https://www.cnblogs.com/tomato0906/articles/4696932.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章