1. 程式人生 > >TCP三次握手、四次斷開與十一種狀態

TCP三次握手、四次斷開與十一種狀態

多線程 半雙工 可靠傳輸 set number 加密 判斷 節點 關閉

一:OSI 模型 Open System Interconnect開放系統互連參考模型,是由ISO(國際標準化組織)定義的,它是個靈活的、穩健的和可互操作的模型,OSI模型的目的是為了規範不同系統的互聯標準,使兩個不同的系統能夠較容易的通信,而不需要改變底層的硬件或軟件的邏輯,OSI模型分為七層,OSI把網絡按照層次分為七層,由下到上分別為物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層。

1.1:第七層:應用層的功能:
為應用軟件提供接口,使應用程序能夠使用網絡服務。常見的應用層協議:
http(80)、ftp(20/21)、smtp(25)、pop3(110)、telnet(23)、dns(53)等

1.2:第六層:表示層的功能:
數據的編碼和解碼、數據的加密和解密、數據和壓縮和解壓縮,常見的標準有JPEG/ASCII等
1.3:第五層:會話層的功能:
建立、管理和終止表示層實體之間的會話連接,在設各或節點之間提供會話控制,它在系統之間協調通信過程,並提供3種不同的方式來組織它們之間的通信:單工、半雙工和全雙工
1.4:第四層:傳輸層的功能:
負責建立端到端的連接,保證報文在端到端之間的傳輸。提供可靠TCP及不可靠UDP的傳輸機制,服務點編址、分段與重組、連接控制、流量控制、差錯控制。
1.5:第三層:網絡層的功能:
定義邏輯地址,邏輯尋址,將數據分組從源傳輸到目的,路徑選擇、路由發現、維護路由表,功能是隔離廣播域;隔離廣播,路由選擇;維護路由表,尋址及轉發,流量管理並連接廣域網
1.6:第二層:數據鏈路層的功能:
組幀、物理編址,將數據幀從鏈路上的一個節點傳遞到另一個節點,流量控制、差錯控制、接入控制
1.7:第一層:物理層的功能:
在介質上傳遞比特流,定義接口和媒體的物理特性,定義比特的表示、數據傳輸速率、信號的傳輸模式(單工、半雙工、全雙工),定義網絡物理拓撲(網狀、星型、環型、總線型等)

二:TCP 協議簡介:

TCP,全稱Transfer Control Protocol,中文名為傳輸控制協議,它工作在OSI的傳輸層,提供面向連接的可靠傳輸服務,TCP的工作主要是建立連接,然後從應用層程序中接收數據並進行傳輸。TCP采用虛電路連接方式進行工作,在發送數據前它需要在發送方和接收方建立一個連接,數據在發送出去後,發送方會等待接收方給出一個確認性的應答,否則發送方將認為此數據丟失,並重新發送此數據。

三:TCP三次握手:

在建立連接的時候,所謂的客戶端與服務端是相對應的,即要看是誰主動連接的誰,如果A主動連接B那麽A就是客戶端而B是服務端,如果返過來B主動連接A,那麽B就是客戶端而A就成了服務端。
3.1:連接過程:
第一次握手:客戶端發送SYN標誌位為1的請求到服務端,並隨機生成一個seq 序列號x,其中seq是隨機產生的數據包的序列號。
第二次握手:服務器收到客戶端請求並返回SYN=1,ACK=1,seq=y,ack=x+1,其中ACK=1表示是響應報文,seq=y是服務器隨機產生的數據包序列號,ack=x+1是確認客戶端序列號有效並返回給客戶端確認。
第三次握手:客戶端收到服務器的確認ack=x+1有效的驗證信息,即在自己發送的序列號基礎之上加了1表示服務器收到並返回,表示第二次連接有效,然後客戶端恢回復ACK=1,seq=x+1,ack=y+1,這是講服務器發來+1後的序列號當做自己的seq序列號,確認號ack使用服務器的隨機號y再加1即ack=y+1,這樣客戶端就完成了第三次的驗證在講數據包發給服務器,服務器收到後驗證確認號是在自己的seq之上加了1,表示沒有問題就開始傳輸數據。
註:
ACK :TCP協議規定,只有ACK=1時有效,也規定連接建立後所有發送的報文的ACK必須為1
Seq:序號,4字節,範圍為0^32—1^32,共4284967296,達到時重新開始計算
在第三次的時候SYN等於0,因為SYN(SYNchronization) 只i在連接建立時用來同步序號,當SYN=1而ACK=0時,表明這是一個連接請求報文,對方若同意建立連接,則應在響應報文中使SYN=1和ACK=1. 因此, SYN置1就表示這是一個連接請求或連接接受報文,鏈路建立成功之後就將標誌位置為0。
SYN(synchronous建立聯機) ACK(acknowledgement 確認)
PSH(push傳送) FIN(finish結束)
RST(reset重置) URG(urgent緊急)
Sequence number(順序號碼) Acknowledge number(確認號碼)
技術分享圖片

四:TCP的四次斷開:

TCP斷開要四次是因為TCP傳輸數全雙工的,即數據是在同一時間內兩條數據鏈路雙向互相傳輸的,因此每個方向都要單獨關閉一次,斷開需要客戶端到服務端斷開一次,而服務端到客戶端也需要斷開一次,這樣的斷開才是完整的斷開,
第一次斷開:客戶方發給服務器一個FIN為1的請求,FIN為1表示是一個斷開連接的請求,即表示數據傳輸完畢請求斷開,並發送seq序列號和Ack確認號。
第二次斷開:服務器收到客戶端請求並返回ACK標誌位為1,Ack為Seq+1等於201,並將對方的Ack作為自己的Seq序列號的確認數據包,biao 接收到請求同意斷開。
第三次斷開:服務器發送ACK=1,FIN=1,Seq等於客戶端第一次請求斷開的Ack確認號+1,即Seq等於501的斷開請求給客戶端。
第四次斷開:客戶端發送ACK=1,Ack在上一步Seq上+1等於502,並使用在第二次斷開中服務器發送的Ack確號201作為本次的序列號發給服務器表示同意斷開,服務器收到後驗證序列號是第二次的,驗證Ack是第三次+1的,確認沒有問題後同意斷開,然後將端口置為TIME_WAIT狀態,等待2 MSL時間後置為關閉狀態,被動方收到主動方的報文確認Ack確認號沒有問題後將端口置為CLOSED,至此端口關閉。
SYN(synchronous建立聯機) ACK(acknowledgement 確認)
PSH(push傳送) FIN(finish結束)
RST(reset重置) URG(urgent緊急)
Sequence number(順序號碼) Acknowledge number(確認號碼)
四次斷開的圖形示意如下:
技術分享圖片

五:TCP端口的十一種連接狀態:

TCP端口一共有十一種狀態,CLOSE_WAIT表示是程序y關閉連接,而TIME_WAIT只占用一個socket連接,到時間之後會釋放,因此大量的CLOSE_WAIT是比大量的TIME_WAIT影響更大,另外還有FIN_WAIT1和FIN_WAIT2,如果有FIN_WAIT2也表示服務有問題,以下是每個端口狀態的含義:
5.1:CLOSED:端口默認是關閉狀態。
5.2:LISTEN: 服務器程序開始監聽一個端口,就是LISTEN狀態。
5.3:SYN_RCVD:三次握手的第二次握手後的端口狀態,是收到了客戶端發送的SYN_SENT數據包之後的狀態,這個狀態很短暫,正常在服務器上是很少看到的,除非服務器故意不發送最後一次握手數據包,服務器返回給客戶端SYN確認之後就會將在自己的端口置為SYN_RCVD。
5.4:SYN_SENT:SYN_SENT狀態表示客戶端已發送SYN=1的請求連接報文,發送之後客戶端就會將自己的端口狀態置為SYN_SENT。
5.5:ESTABLISHED:表示已經連接成功,客戶端收到服務器的確認報文會回復服務器,然後就將端口置為ESTABLISHED,服務器第三次收到客戶端的Ack確認就會將端口置為ESTABLISHED並開始傳輸數據。
5.6:FIN_WAIT_1:出現在主動關閉方,FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,當任意一方想主動關閉連接,向對方發送了FIN=1的斷開連接請求報文,此時該SOCKET即 進入到FIN_WAIT_1狀態。而當對方回應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬 上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。
5.7:FIN_WAIT_2:出現在主動關閉方,當被動方回應FIN_WAIT_1的ACK報文後,則進入到FIN_WAIT_2狀態
5.8:TIME_WAIT:出現在主動關閉方,表示收到了對方的FIN請求關閉報文,並發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。
5.9:CLOSING: 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你發送FIN報文後,按理來說是應該先收到(或同時收到)對方的 ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什 麽情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方幾乎在同時close一個SOCKET的話,那麽就出現了雙方同時發送FIN報 文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連接。
5.10:CLOSE_WAIT: 表示在等待關閉端口,這種狀態存在於被動關閉的一方。
5.11:LAST_ACK: 是被動關閉方在主動關閉一方在發送FIN報文後,最後等待對方的ACK報文,當再次收到ACK報文後,也即可以進入到CLOSED可用狀態了。
5.12:區分主動斷開和被動端口方的端口狀態:
主動端口方:SYN_SENT、FIN_WAIT1、FIN_WAIT2、CLOSING、TIME_WAIT 。
被動斷開方:LISTEN、SYN_RCVD、CLOSE_WAIT、LAST_ACK 。
都具有的:CLOSED 、ESTABLISHED 。
技術分享圖片
5.13:關於優化:
socket就是一個TCP連接,包括源地址、源端口、目標地址、目標端口和協議(TCP|UDP),0端口是保留不能使用的,因此服務器的最大端口使用數量為63353個,最大65536個端口是因為TCP報文頭部有個端口長度為2^16次方等於65536,查看當前打開的端口範圍# cat /proc/sys/net/ipv4/ip_local_port_range,單個IP地址能接受的最大並發為六萬多,1萬個TIME_WAIT大約使用1MB的內存CPU占用更小,因此資源使用很小可以忽略不計,但是會占用一個socket,可以通過在負載上配置多個公網IP地址以提高高並發的問題,
[[email protected] ~]# cat /proc/sys/net/ipv4/tcp_tw_recycle
0 #用於快速回收處於TIME_WAIT狀態的socket以便重新分,在負載服務器不能打開,會導致通過nat上網的後續用戶無法打開網頁,因為後面的訪問用戶時間戳小於前面的用戶,會導致數據包被負載服務器丟棄,可以在內網使用,但是通常建議關閉。
[[email protected] ~]# cat /proc/sys/net/ipv4/tcp_tw_reuse
0 #kernel會復用處於TIME_WAIT狀態的socket,即允許將TIME_WAIT狀態得socket用於直接新的TCP連接,負載服務器建議打開
[[email protected] ~]# cat /proc/sys/net/ipv4/tcp_timestamps
1 #記錄數據包的時間戳,判斷是新的數據包還是舊的,如果是舊的就丟棄,配合上面兩個選項的時候一定要打開才生效。

六:Apache的工作模式:

Apache 2.X 支持插入式並行處理模塊,稱為多路處理模塊(Multi-Processing Modules,MPM),在linux 系統,有3個不同類型的版本可供選擇,具體如下:
6.1:Prefork MPM: 預派生模式,有一個主控制進程,然後生成多個子進程,使用select模型,最大並發1024,每個子進程有一個獨立的線程響應用戶請求,相對比較占用內存,但是比較穩定,可以設置最大和最小進程數,是最古老的一種模式,也是最穩定的模式,適用於訪問量不是很大的場景。
優點:穩定
缺點:慢,占用資源,不適用於高並發場景
技術分享圖片
配置文件原內容:
#prefork MPM
#StartServers: number of server processes to start
#MinSpareServers: minimum number of server processes which are kept spare
#MaxSpareServers: maximum number of server processes which are kept spare
#MaxRequestWorkers: maximum number of server processes allowed to start
#MaxConnectionsPerChild: maximum number of connections a server process serves
#before terminating

<IfModule mpm_prefork_module>
StartServers 5 #定義apache服務在啟動時啟動的子進程數量
MinSpareServers 5 #定義最小空閑進程數,空閑進程就是沒有處理用戶請求的進程數
MaxSpareServers 10 #定義最大空閑進程數
MaxRequestWorkers 250 #定義在prefork模式下的最大並發連接數,表示了apache的最大並發處理能力,超過的連接請求將被排隊等候處理。
MaxConnectionsPerChild 0 #進程生命周期內,處理的最大請求數目。達到該數目後,進程將死掉。如果設置為0,表示沒有限制。該參數的意義在於,避免了可能存在的內存泄露帶來的系統問題。
</IfModule>

如果確定合適的MaxRequestWorkers呢?
首先,通過top命令查看apache進程占用的資源,主要看%CPU和%MEM這兩個指標,例如,每個進程的CPU占用率不超過1%,每個進程的內存占用率不超過2%,考慮內存限制,比較合適的apache進程數量為50個,然後,逐步測試最大值。通過觀測得來的CPU和內存的指標有一定的誤差,一般可以適當調節這個數值,例如調到1.5或者2倍,再通過峰值場景下的機器是否卡頓來判斷是繼續上調還是下調。
6.2:woker MPM:是一種多進程和多線程混合的模型,有一個控制進程,啟動多個子進程,每個子進程裏面包含固定的線程,使用線程程來處理請求,當線程不夠使用的時候會再啟動一個新的子進程,然後在進程裏面再啟動線程處理請求,由於其使用了線程處理請求,因此可以承受更高的並發。
技術分享圖片
優點:相比prefork 占用的內存較少,可以同時處理更多的請求
缺點:使用keep-alive的長連接方式,某個線程會一直被占據,即使沒有傳輸數據,也需要一直等待到超時才會被釋放。如果過多的線程,被這樣占據,也會導致在高並發場景下的無服務線程可用。(該問題在prefork模式下,同樣會發生)
配置文件原內容詳解:
#worker MPM
#StartServers: initial number of server processes to start
#MinSpareThreads: minimum number of worker threads which are kept spare
#MaxSpareThreads: maximum number of worker threads which are kept spare
#ThreadsPerChild: constant number of worker threads in each server process
#MaxRequestWorkers: maximum number of worker threads
#MaxConnectionsPerChild: maximum number of connections a server process serves
#before terminating

<IfModule mpm_worker_module>
StartServers 3 # #定義apache服務在啟動時啟動的子進程數量,默認是3個
MinSpareThreads 75 # 整個控制進程保持最小數的空閑線程數
MaxSpareThreads 250 # 整個控制進程保持最大數的空閑線程數
#ThreadLimit 64 # 每個子進程可以啟動的線程數量上限值,默認沒有設置
ThreadsPerChild 25 # 每個子進程啟動的線程默認數量,開啟啟動兩個子進程每個子進程25個 線程,就是apache 啟動後開啟25個線程。
MaxRequestWorkers 400 # 所有子進程加起來的線程數量最大值,數量等於最大啟動的進程數*ThreadsPerChild(每個進程的線程數)
MaxConnectionsPerChild 0 # 每個子進程被請求多少次服務後被kill掉重新生成一個新的子進程,為了解決內存回收方面的問題,0為不設置
</IfModule>
6.3:event MPM:Apache中最新的模式,屬於事件驅動模型(epoll),每個進程響應多個請求,在現在版本裏的已經是穩定可用的模式。它和worker模式很像,最大的區別在於,它解決了keep-alive場景下,長期被占用的線程的資源浪費問題(某些線程因為被keep-alive,空掛在哪裏等待,中間幾乎沒有請求過來,甚至等到超時)。event MPM中,會有一個專門的線程來管理這些keep-alive類型的線程,當有真實請求過來的時候,將請求傳遞給服務線程,執行完畢後,又允許它釋放。這樣增強了高並發場景下的請求處理能力。
event只在有數據發送的時候才開始建立連接,連接請求才會觸發工作線程,即使用了TCP的一個選項,叫做延遲接受連接TCP_DEFER_ACCEPT,加了這個選項後,若客戶端只進行TCP連接,不發送請求,則不會觸發Accept操作,也就不會觸發工作線程去幹活,進行了簡單的防***(TCP連接),可以使用Telnet進行測試驗證:
主機192.168.10.130為客戶端機器,192.168.10.131為apache服務器機器使用event模式:
在192.168.10.130上telnet 192.168.10.131 80,然後在192.168.10.130客戶端機器上使用netstat查看,發現連接已經建立,處於ESTABLISHED狀態,然後再到apache服務器192.168.10.131使用netstat查看,發現是處於SYN_RECV狀態。
技術分享圖片
優點:單線程響應多請求,占據更少的內存,高並發下表現更優秀,會有一個專門的線程來管理keep-alive類型的線程,當有真實請求過來的時候,將請求傳遞給服務線程,執行完畢後,又允許它釋放
缺點:沒有線程安全控制
配置文件內容:
#event MPM
#StartServers: initial number of server processes to start
#MinSpareThreads: minimum number of worker threads which are kept spare
#MaxSpareThreads: maximum number of worker threads which are kept spare
#ThreadsPerChild: constant number of worker threads in each server process
#MaxRequestWorkers: maximum number of worker threads
#MaxConnectionsPerChild: maximum number of connections a server process serves
#before terminating
<IfModule mpm_event_module>
StartServers 3 #apache服務啟動的子進程數,默認3個
MinSpareThreads 75 #控制進程保持最小的空閑線程數
MaxSpareThreads 250 #控制進程保持的最大空閑線程數
ThreadsPerChild 25 #每個子進程啟動的線程數
MaxRequestWorkers 400 #並發最大請求數,也就是所有子進程加起來的線程數量,woker模式下的400就是並發400,但是由於是異步處理請求的,因此這裏的400比woker模型下的並發處理速度要快很多,因為event省略了工作線程的會話保持。
MaxConnectionsPerChild 0 #每個子進程請求多少次以後被kill掉重新生成一個新的子進程。
</IfModule>

TCP三次握手、四次斷開與十一種狀態