1. 程式人生 > >linux網路程式設計之TCP狀態轉換及埠複用

linux網路程式設計之TCP狀態轉換及埠複用

(1)TCP狀態轉換圖

         

    其中圖中分為三種狀態:實線代表的主動發起連線,虛線代表的被動發起連線,細實線代表的可以雙向發起連線的狀態。

主動發起連線方狀態變化:1)主動發起連線的一方傳送SYN標誌位,進入SYN_SENT狀態,等待接收被髮起連線方傳送ACK應答和資料包序號,接收到ACK應答後,同時向被被髮起連線方傳送ACK應答,表示資料已經接收到,同一發起連線,此時進入ESTABLISHED狀態,表示三次握手完成。2)主動發起連線的一方向另一方傳送FIN標誌位,請求關閉連線,立即進入FIN_WATI_1,等待被動發起連線方傳送ACK應答訊號,主動發起連線方接收到ACK應答訊號後,進入FIN_WATI_2狀態,代表主動發起連線端半關閉完成。此時,如果被動連線方傳送FIN訊號請求關閉連線,主動發起連線的一方會發送一個ACK應答訊號同意關閉,但是此時不確定被動發起連線方是否收到訊號(因為主動發起連線方已經關閉),所以要等待一個2MSL時間(確保最後傳送的一個ACK應答訊號被接收到),2MSL時間一到,被動連線方關閉,四次揮手完成。

被動發起連線方狀態變化:1)被動發起連線方處於監聽狀態,等待連線,當被動發起連線方接收到主動方SYN狀態請求連線時,被動發起連線方會發送一個ACK應答同時攜帶自己的資料報序號給主動方,進入SYN_RCVD狀態,等待主動方傳送ACK應答訊號,當接收到主動方發起的ACK應答訊號時,被動發起連線方進入ESTABLISHED狀態,表示三次握手完成。2)當主動方傳送FIN請求關閉時,被動連線方接收FIN並同時向主動方傳送ACK應答,同意關閉,此時被動連線方進入CLOSE_WAIT狀態。如果此時被動連線方傳送FIN訊號,則進入LAST_ACK狀態,等待主動方的應答訊號,當接收到主動方的應答訊號,被動方關閉,四次揮手完成。

雙向連線狀態:1)當被動發起連線方進入SYN_RCVD狀態,等待主動發起方傳送ACK應答訊號時,此時如果網路中斷,則三次握手中斷,重新進行三次握手,被接受方傳送RST訊號,重新連線。2)主動發起連線方接收到FIN訊號進入FIN_WAIT_1狀態,此時如果主動接收到ACK和FIN訊號,同時給被動方傳送ACK應答訊號,則主動方進入TIME_WAIT狀態,等待2MSL時間關閉檔案。如果只收到ACK應答訊號和FIN訊號,則會進入CLOSING狀態,當主動傳送ACK應答訊號時,主動方進入TIME_WAIT狀態,等待2MSL時間關閉檔案。

(2)C/S模型的TCP狀態圖

         

(3)半關閉

            當TCP連結中A傳送FIN請求關閉,B端迴應ACK後(A端進入FIN_WAIT_2狀態),B沒有立即傳送FIN給A,此時A處於半關閉狀態,A可以接收B傳送的資料,但是A不能向B傳送資料了。

           使用close關閉檔案描述符只是中止一個連線,它減少的只是描述符的引用計數,並不直接關閉連線,當引用計數達到0時,才關閉連線。而使用shutdown不考慮描述符的引用計數,直接關閉描述符,也可以中止一個方向的連線,只中止讀或者寫。

            #include<sys/socket.h>

            int   shutdown(int sockfd,int how)

           引數:how        SHUT_RD(0):關閉套接字讀功能快取區

                                      SHUT_WR(1):關閉套接字寫功能快取區

                                      SHUT_RDWR(2):關閉套接字讀寫功能快取區

(4)埠複用

             當伺服器斷開連線時,實際上此時伺服器使用的埠處於TIME_WAIT狀態,需要等待2MSL時間才能重新被利用。如果想要在伺服器斷開連線時埠可以被使用,則需要使用埠複用功能,具體方法是使用setsockopt()設定socket描述符選項的S0_REUSEADDR為1,表示允許建立埠號相同,但IP地址不同的多個socket描述符。

           在server程式碼中的socket()和bind()之間插入程式碼:

                           int opt=1;

                           setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));