1,查看tcp狀態工具
工欲善其事必先利其器,先了解下查看tcp狀態的工具
1),netstat
Netstat 命令用於顯示各種網絡相關信息,如網絡連接,路由表,接口狀態 (Interface Statistics),masquerade 連接,多播成員 (Multicast Memberships) 等等。
-a (all)顯示所有選項,默認不顯示LISTEN相關
-t (tcp)僅顯示tcp相關選項
-u (udp)僅顯示udp相關選項
-n 拒絕顯示別名,能顯示數字的全部轉化成數字。
-l 僅列出有在 Listen (監聽) 的服務狀態
-p 顯示建立相關鏈接的程序名
-r 顯示路由信息,路由表
-e 顯示擴展信息,例如uid等
-s 按各個協議進行統計
-c 每隔一個固定時間,執行該netstat命令。
2)、lsof -i:port 可以檢測到打開套接字的狀況
lsof(list open files)是一個列出當前系統打開文件的工具
3)、 sar -n SOCK 查看tcp創建的連接數 (System Activity Reporter)
4)、tcpdump -iany tcp port 9000 對tcp端口為9000的進行抓包
5)traceroute:raceroute 跟蹤數據包到達網絡主機所經過的路由工具
2 tcp狀態
LISTENING:偵聽來自遠方的TCP端口的連接請求
Server端調用bind操作,將監聽套接字與指定的地址和端口關聯,然后又調用listen函數,系統會為其分配未完成隊列和完成隊列,此時的監聽套接字可以接受Client的連接,監聽套接字狀態處於LISTEN狀態。
SYN_SEND:客戶端通過應用程序調用connect進行active open.於是客戶端tcp發送一個SYN以請求建立一個連接.之后狀態置為SYN_SENT
SYN_RCVD: 服務端收到SYN,將標志位SYN和ACK置1,發送給客戶端, 此時為SYN_RCVD狀態。
SYN Flood的攻擊原理是:
在進行三次握手時,攻擊軟件向被攻擊的服務器發送SYN連接請求(握手的第一步),但是這個地址是偽造的,如攻擊軟件隨機偽造了51.133.163.104、65.158.99.152等等地址。服務器在收到連接請求時將標志位ACK和SYN置1發送給客戶端(握手的第二步),但是這些客戶端的IP地址都是偽造的,服務器根本找不到客戶機,也就是說握手的第三步不可能完成。
ESTABLISHED:代表一個打開的連接。
netstat -nat |grep 9502或者使用lsof -i:9502可以檢測到。
當客戶端未主動close的時候就斷開連接:即客戶端發送的FIN丟失或未發送。
這時候若客戶端斷開的時候發送了FIN包,則服務端將會處於CLOSE_WAIT狀態;
這時候若客戶端斷開的時候未發送FIN包,則服務端處還是顯示ESTABLISHED狀態;
結果客戶端重新連接服務器。
而新連接上來的客戶端(也就是剛才斷掉的重新連上來了)在服務端肯定是ESTABLISHED; 如果客戶端重復的上演這種情況,那么服務端將會出現大量的假的ESTABLISHED連接和CLOSE_WAIT連接。
最終結果就是新的其他客戶端無法連接上來,但是利用netstat還是能看到一條連接已經建立,並顯示ESTABLISHED,但始終無法進入程序代碼。
關閉(四次揮手)
FIN_WAIT1:
主動關閉(active close)端應用程序調用close,於是其TCP發出FIN請求主動關閉連接,之后進入FIN_WAIT1狀態./* The socket is closed, and the connection is shutting down. 等待遠程TCP的連接中斷請求,或先前的連接中斷請求的確認 */
如果服務器出現shutdown再重啟,使用netstat -nat查看,就會看到很多FIN-WAIT-1的狀態。就是因為服務器當前有很多客戶端連接,直接關閉服務器后,無法接收到客戶端的ACK。
CLOSE-WAIT:等待從本地用戶發來的連接中斷請求
被動關閉(passive close)端TCP接到FIN后,就發出ACK以回應FIN請求(它的接收也作為文件結束符傳遞給上層應用程序),並進入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待從本地用戶發來的連接中斷請求 */
FIN-WAIT-2:從遠程TCP等待連接中斷請求
主動關閉端接到ACK后,就進入了FIN-WAIT-2 ./* Connection is closed, and the socket is waiting for a shutdown from the remote end. 從遠程TCP等待連接中斷請求 */
這就是著名的半關閉的狀態了,這是在關閉連接時,客戶端和服務器兩次握手之后的狀態。在這個狀態下,應用程序還有接受數據的能力,但是已經無法發送數據,但是也有一種可能是,客戶端一直處於FIN_WAIT_2狀態,而服務器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態
LAST-ACK:等待原來的發向遠程TCP的連接中斷請求的確認
被動關閉端一段時間后,接收到文件結束符的應用程序將調用CLOSE關閉連接。這導致它的TCP也發送一個 FIN,等待對方的ACK.就進入了LAST-ACK . /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原來發向遠程TCP的連接中斷請求的確認 */
使用並發壓力測試的時候,突然斷開壓力測試客戶端,服務器會看到很多LAST-ACK。
TIME-WAIT:等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認
在主動關閉端接收到FIN后,TCP就發送ACK包,並進入TIME-WAIT狀態。/* The socket is waiting after close to handle packets still in the network.等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認 */
TIME_WAIT等待狀態,這個狀態又叫做2MSL狀態,說的是在TIME_WAIT2發送了最后一個ACK數據報以后,要進入TIME_WAIT狀態,這個狀態是防止最后一次握手的數據報沒有傳送到對方那里而准備的(注意這不是四次握手,這是第四次握手的保險狀態)。這個狀態在很大程度上保證了雙方都可以正常結束,但是,問題也來了。
由於插口的2MSL狀態(插口是IP和端口對的意思,socket),使得應用程序在2MSL時間內是無法再次使用同一個插口的,對於客戶程序還好一些,但是對於服務程序,例如httpd,它總是要使用同一個端口來進行服務,而在2MSL時間內,啟動httpd就會出現錯誤(插口被使用)。為了避免這個錯誤,服務器給出了一個平靜時間的概念,這是說在2MSL時間內,雖然可以重新啟動服務器,但是這個服務器還是要平靜的等待2MSL時間的過去才能進行下一次連接。
client/server兩條路線講述TCP狀態遷移路線圖:


1.為什么建立連接協議是三次握手,而關閉連接卻是四次握手呢?
這是因為服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求后,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文里來發送。但關閉連接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你所有的數據都全部發送給對方了,所以你可以未必會馬上會關閉SOCKET,也即你可能還需要發送一些數據給對方之后,再發送FIN報文給對方來表示你同意現在可以關閉連接了,所以它這里的ACK報文和FIN報文多數情況下都是分開發送的。
2.為什么TIME_WAIT狀態還需要等2MSL后才能返回到CLOSED狀態?
這是因為雖然雙方都同意關閉連接了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣):
一方面是可靠的實現TCP全雙工連接的終止,也就是當最后的ACK丟失后,被動關閉端會重發FIN,因此主動關閉端需要維持狀態信息,以允許它重新發送最終的ACK。
另一方面,但是因為我們必須要假想網絡是不可靠的,你無法保證你最后發送的ACK報文會一定被對方收到,因此對方處於LAST_ACK狀態下的SOCKET可能會因為超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的ACK報文。
TCP在2MSL等待期間,定義這個連接(4元組)不能再使用,任何遲到的報文都會丟棄。設想如果沒有2MSL的限制,恰好新到的連接正好滿足原先的4元組,這時候連接就可能接收到網絡上的延遲報文就可能干擾最新建立的連接。
3、發現系統存在大量TIME_WAIT狀態的連接,可以通過調整內核參數解決:vi /etc/sysctl.conf 加入以下內容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后執行 /sbin/sysctl -p 讓參數生效。
net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉;
net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間
服務器端主動關閉:
1)當服務器的服務因為某種原因,進程提前終止時會向客戶 TCP 發送 FIN 分節,服務器端處於FIN_WAIT1狀態。
2)客戶TCP回應ACK后,服務TCP將轉入FIN_WAIT2狀態。
3)此時如果客戶進程沒有處理該 FIN (如阻塞在其它調用上而沒有關閉 Socket 時),則客戶TCP將處於CLOSE_WAIT狀態。
4)當客戶進程再次向 FIN_WAIT2 狀態的服務 TCP 發送數據時,則服務 TCP 將立刻響應 RST。
TIME_WAIT狀態存在的理由:
1)可靠地實現TCP全雙工連接的終止:(即在TIME_WAIT下等待2MSL,只是為了盡最大努力保證四次握手正常關閉)。
TCP協議規定,對於已經建立的連接,網絡雙方要進行四次握手才能成功斷開連接,如果缺少了其中某個步驟,將會使連接處於假死狀態,連接本身占用的資源不會被釋放。
在進行關閉連接四路握手協議時,最后的ACK是由主動關閉端發出的,如果這個最終的ACK丟失,服務器將重發最終的FIN,因此客戶端必須維護狀態信息允許它重發最終的ACK。如果不維持這個狀態信息,那么客戶端將響應RST分節,因而,要實現TCP全雙工連接的正常終止,必須處理終止序列四個分節中任何一個分節的丟失情況,主動關閉的客戶端必須維持狀態信息進入TIME_WAIT狀態。
我們看客戶端主動關閉服務器被動關閉四次握手的流程:
1、 客戶端發送FIN報文段,進入FIN_WAIT_1狀態。
2、 服務器端收到FIN報文段,發送ACK表示確認,進入CLOSE_WAIT狀態。
3、 客戶端收到FIN的確認報文段,進入FIN_WAIT_2狀態。
4、 服務器端發送FIN報文端,進入LAST_ACK狀態。
5、 客戶端收到FIN報文端,發送FIN的ACK,同時進入TIME_WAIT狀態,啟動TIME_WAIT定時器,超時時間設為2MSL。
6、 服務器端收到FIN的ACK,進入CLOSED狀態。
7、 客戶端在2MSL時間內沒收到對端的任何響應,TIME_WAIT超時,進入CLOSED狀態。
如果不考慮報文延遲、丟失,確認延遲、丟失等情況,TIME_WAIT的確沒有存在的必要。當網絡在不理想的情況下通常會有報文的丟失延遲發生,讓我們看下面的一個特例:
客戶端進入發送收到四次握手關閉的最后一個ACK后,進入TIME_WAIT同時發送ACK,如果其不停留2MSL時間,而是馬上關閉連接,銷毀連接上的資源,當發送如下情況時,將不能正常的完成四次握手關閉:
客戶端發送的ACK在網路上丟失,這樣服務器端收不到最后的ACK,重傳定時器超時,將重傳FIN到客戶端,由於客戶端關於該連接的所有資源都釋放,收到重傳的FIN后,它沒有關於這個FIN的任何信息,所以向服務器端發送一個RST報文端,服務器端收到RST后,認為搞連接出現了異常(而非正常關閉)。
所以,在TIME_WAIT狀態下等待2MSL時間端,是為了能夠正確處理第一個ACK(最長生存時間為MSL)丟失的情況下,能夠收到對端重傳的FIN(最長生存時間為MSL),然后重傳ACK。
是否只要主動關閉方在TIME_WAIT狀態下停留2MSL,四次握手關閉就一定正常完成呢?
答案是否定的?可以考慮如下的情況,
TIME_WAIT狀態下發送的ACK丟失,LAST_ACK時刻設定的重傳定時器超時,發送重傳的FIN,很不幸,這個FIN也丟失,主動關閉方在TIME_WAIT狀態等待2MSL沒收到任何報文段,進入CLOSED狀態,當此時被動關閉方並沒有收到最后的ACK。所以即使要主動關閉方在TIME_WAIT狀態下停留2MSL,也不一定表示四次握手關閉就一定正常完成。
2)確保老的報文段在網絡中消失,不會影響新建立的連接
考慮如下的情況,主動關閉方在TIME_WAIT狀態下發送的ACK由於網絡延遲的原因沒有按時到底(但並沒有超過MSL的時間),導致被動關閉方重傳FIN,在FIN重傳后,延遲的ACK到達,被動關閉方進入CLOSED狀態,如果主動關閉方在TIME_WAIT狀態下發送ACK后馬上進入CLOSED狀態(也就是沒有等待)2MSL時間,則上述的連接已不存在:
現在考慮下面的情況,假設客戶端(192.186.0.1:23) 到服務器192.168.1.1:6380)的TCP連接, 由於連接已關閉,我們可以馬上建立一個相同的IP地址和端口之間的TCP連接,並且這個連接也是客戶端(192.186.0.1:23) 到服務器192.168.1.1:6380),那么當上一個連接的重傳FIN到達主動關閉方時,被新的連接所接受,這將導致新的連接被復位,很顯然,這不是我們希望看到的事情。
引用:https://blog.csdn.net/hguisu/article/details/38700899
