(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));