上篇介紹了socket編程的準備知識,是否是有一種很想立刻就開始瞭解網絡編程,甚至開始寫點代碼的感受,彆着急,網絡編程中還有一個比較重要的概念是TCP/IP,中文名稱叫網絡傳輸協議,本質上,TCP/IP是一種協議,同時也是網絡編程中最重要的協議之一。TCP/IP涉及到的內容實在太多,無奈筆者才疏學淺,沒法把整個TCP/IP介紹給你們,這篇文章的目的主要是基於上一篇文章的前提下,介紹TCP鏈接三次握手和斷開鏈接四次揮手究竟作了什麼?socket的狀態有哪些?在各個API執行的過程當中,socket的狀態是怎麼變化的?但願經過這篇文章,能讓你們對在TCP鏈接創建與斷開過程當中,socket的整個狀態變化流程有更深刻的瞭解。web
SYN : 同步序列編號,Synchronize Sequence Numbers,僅在三次握手創建TCP鏈接時有效。表示一個新的TCP鏈接請求。編程
ACK : 確認編號,Acknowledgement Number,對TCP請求的確認標誌,同時提示對端系統已經成功接收全部數據。服務器
FIN : 結束標誌,FINISH,用來結束一個TCP會話,但對應端口仍處於開放狀態,準備接收後續數據。網絡
創建一次鏈接會有下面的流程併發
1)服務器經過socket(初始化socket)、bind(綁定ip端口)、listen(開始監聽服務)完成一次socket鏈接的創建,並調用accept函數準備好接收外部請求鏈接,這一步被稱爲被動打開socket
2)客戶端經過socket(初始化socket)完成了鏈接創建,調用connect函數發起主動打開,此時客戶端會發送一個SYN分節J給服務器,J的做用是告訴服務器,在接下來的數據傳輸過程當中,J是客戶端在鏈接中傳輸數據的初始序列號函數
3)服務器收到客戶端的SYN分節後,須要回覆確認信號ACK,J+1,表明服務器已經收到客戶端的請求,且已經確認了客戶端的初始序列號,同時服務器會發送SYN分節K給客戶端,K的做用是告訴客戶端,在接下來的數據傳輸過程當中,K是服務器在鏈接中傳輸數據的初始序列號測試
4)客戶端收到服務器的SYN分節後,回覆確認信號(ACK)K+1。鏈接創建成功。動畫
整個創建鏈接過程至少須要三個分節,所以被稱爲TCP三路握手。下面是TCP三次握手的流程圖:網絡傳輸協議
TCP經過三次握手創建鏈接,然而,斷開鏈接須要四次握手,TCP斷開鏈接的流程描述以下:
一、客戶端應用程序調用close函數,TCP中,稱首先調用close的那一端爲主動關閉,主動關閉的這一端發送FIN分節,意味着已經完成發送數據了;
二、另外一端(即服務器),接收到關閉請求,也收到FIN分節,開始執行被動關閉操做,稱爲被動關閉的一端。這個FIN分節由TCP確認,發送一個確認分節ACK給客戶端,收到的FIN同時也是做爲文件結束符傳遞給應用,意味着應用程序在接收了FIN以後就不會再接收鏈接上的數據;
三、以後,接收到文件結束符的應用程序會關閉它的socket,服務端的TCP也會發送一個FIN分節;
四、客戶端接收到FIN分節,並確認最後的關閉操做,發送ACK分節給服務端。
整個鏈接過程當中,每一端的關閉和確認關閉都各自須要一個FIN和ACK分節,整個過程一般共須要4個分節,所以也稱爲TCP四次握手。下面是TCP關閉鏈接四次握手的流程圖:
實際上,網絡上的傳輸是沒有鏈接的,包括TCP也是同樣,TCP所謂的"鏈接"與"斷開鏈接",其實只是一種虛擬的叫法,只不過是在通信的雙方維護一個"鏈接狀態",讓它看上去好像有鏈接同樣,因此,瞭解TCP的狀態變換是很是重要的,接下來介紹socket的狀態以及在TCP創建鏈接與斷開鏈接過程當中,socket狀態的變化。
socket共定義了11種狀態:LISTEN、SYN-SENT、SYN-RECEIVED、ESTABLISHED、FIN-WAIT-一、FIN-WAIT-一、CLOSE_WAIT、FIN_WAIT、LAST-ACK、TIME-WAIT、CLOSING、CLOSED。
咱們假定A服務請求鏈接B服務。
LISTEN:開始創建鏈接,此時socket已經初始化成功,正在等待鏈接
SYN-SENT:A成功發送鏈接請求給B,等待對方響應
SYN-RECEIVED:B接收到A的鏈接請求,並回復了確認進行鏈接給A,此狀態表示正在等待A也回覆確認收到此消息
ESTABLISHED:表示鏈接已經成功創建;這個狀態是鏈接階段中進行數據傳輸的正常狀態
FIN-WAIT-1:等待主動斷開鏈接請求的確認,或者併發請求被拒絕的斷開鏈接,這種狀態一般持續時間很短,比較難捕捉
FIN-WAIT-2:等待B斷開鏈接操做,這個狀態一般持續時間也很短,可是若是B發生阻塞或者其餘緣由沒有關閉鏈接,那麼這個狀態就會持續較長時間
CLOSE-WAIT:B已經收到了A的斷開鏈接請求,正在等待本地應用程序發送斷開鏈接請求
CLOSING:A正在等待B的關閉鏈接確認信號,當A接收到本地程序斷開鏈接的請求後,就發送斷開鏈接請求給B,並進入此狀態
LAST-ACK:B等待斷開鏈接的確認信號
TIME-WAIT:等待一段時間,確認B接收到A的關閉鏈接確認信號
CLOSED:鏈接徹底關閉
那麼在一個完整的TCP鏈接過程,TCP的狀態是怎麼轉換的呢?
先來看看下面這張圖,是UNIX網絡編程中,TCP狀態變化的經典流程圖:
在server端,調用socket函數建立一個sockect,函數返回一個socket文件描述符,調用bind函數綁定ip地址和端口,以後調用listen函數,scokect變成正在監聽的socket,進入LISTEN狀態,並調用accept等待請求(想要測試LISTEN狀態,能夠創建socket=>bind=>listen,而後sleep10秒以後退出,啓動server以後立刻用netstat命令能夠看到)
客戶端調用connect,主動打開文件描述符,請求創建鏈接,此時會觸發TCP的三次握手,進入SYN-SENT狀態
此時服務器調用了accept正在阻塞階段,接收到客戶端的鏈接請求後,進入SYN-RECEIVED狀態,回覆確認報文給客戶端,等待客戶端確認鏈接
客戶端收到服務器的鏈接確認報文SYN後,此時TCP已經完成了三次握手,connect函數返回,確認創建鏈接,轉成ESTABLISHED狀態,併發送確認報文ACK給服務器。(當第二次握手完成,握手步驟的第二個segment被client接收到的時候,connect函數返回。)
在服務器側,接收到客戶端的確認報文,accept也收到返回,服務器也進入ESTALISHED狀態。(握手步驟的第三個分節被server接收到的時候,accept函數返回,即connect返回後通過一半的RTT時間才返回。)
客戶端和服務端成功創建"鏈接"後,就進行開始通訊,此時會調用read/write函數進行讀寫數據,讀寫數據完畢後,就準備關閉鏈接
假定客戶端應用程序,收到了服務器的響應報文,完成了通訊過程,準備關閉應用,調用close函數發起主動關閉,此時客戶端進入FIN-WAIT1狀態,發送FIN分節到服務器,等待服務器確認
服務端收到斷開鏈接請求分節FIN(M),此時read函數返回0,服務器準備執行關閉操做,再也不接收任何數據,併發送確認報文ACK(M+1)給客戶端
客戶端收到確認分節後,表示服務器已經接收到斷開鏈接請求,此時不會再發送數據並等待服務器斷開鏈接,進入FIN-WAIT2狀態
服務器發送確認斷開鏈接後,調用close函數,斷開鏈接,close函數成功返回後,發送FIN分節給客戶端,進入LASK-ACK狀態,等待客戶端的確認
客戶端收到服務器的斷開鏈接分節FIN(N)後,發送確認分節ACK給服務器,並進入TIME-WAIT狀態,此時會等待足夠的時間,大約是最長分節生命期的2倍(2MSL),確認服務器收到斷開鏈接的確認分節,以後就會消失。 服務器收到客戶端的斷開鏈接的確認分節ACK(N+1)後,表示鏈接已經徹底斷開了,此時進入CLOSED狀態
看完上面的一大段文字可能有點枯燥,甚至有點懵,來看看這張動畫圖:
本次主要介紹了TCP狀態,以及在TCP鏈接創建和斷開過程當中,TCP狀態的變化,掌握了這個,對理解網絡編程中,各個流程的狀態有比較大的幫助,好比在排查服務是否啓動的時候,就能夠經過netstat -nlp | grep '端口號'
,查看服務的狀態描述字符串,若是是LISTEN狀態表示服務已經正常啓動,若是服務處於其餘狀態,則能夠經過服務狀態來進一步排查問題。
原創文章,文筆有限,才疏學淺,文中如有不正之處,萬望告知。
若是本文對你有幫助,請點個贊吧,謝謝^_^
更多精彩內容,請關注我的公衆號。