TCP三次握手和四次揮手全過程


TCP是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立連接:

SYN:同步標志。該標志僅在三次握手建立TCP連接時有效。
ACK:確認標志。同時提示遠端系統已經成功接收所有數據
PSH: 表示有DATA數據傳輸
FIN: 結束標志
RST: reset表示連接重置
URG: urgent緊急指針字段值有效

建立TCP連接
三次握手: TCP的連接建立是一個三次握手的過程,目的是通信雙方確認開始序列,以便后續通信的有序進行。
1. 連接請求: 連接開始時,客戶端(Client)發送SYN包,並包含了一個初始的seq=a的值,客戶端(Client)進入SYN_SENT狀態,等待服務端(Server)確認
2. 請求確認: 服務端(Server)收到數據包后知道客戶端(Client)請求建立連接,將回復一個SYN包,並包含了對上一個a包的回應信息ACK,ACK=a+1.然后還包含了一個隨機的自己初始seq=b,服務端進入SYN_RCVD狀態
3. 連接確認: 客戶端(Client)收到確認SYN包后,檢查ack是否為a+1,如果正確將回復發送一個ACK包,其中包含了一個ACK=b+1,和一個seq=a+1,服務端(Server)檢查ACK是否為b+1,如果正確則建立連接,Client和Server進入ESTABLISHED狀態,完成三次握手,Client和Server之間開始傳輸數據

斷開TCP連接
四次揮手: 即終止TCP連接,需要Client端和Server端總共發送4個包已確認連接的斷開
1. Client發送一個FIN並包含一個隨機的seq=a,主動關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態
2. Server收到FIN后,發送一個ACK並包含一個seq=a+1給Client,Server進入CLOSE_WAIT狀態。
3. Server發送一個FIN並包含一個隨機的seq=b和一個ACK=a+1,用來關閉Server到Client的數據傳輸,Server進入LAST_ACK狀態。
4. Client收到FIN后,Client進入TIME_WAIT狀態,接着發送一個ACK並包含一個seq=b+1給Server,Servr收到ACK包后進入CLOSED狀態,完成四次揮手

TCP的連接請為什么會采用三次握手,若采用二次握手可以嗎?
采用三次握手是為了防止失效的連接請求報文段突然又傳送到Server端主機,因而產生錯誤。失效的連接請求報文段是指:
Client發出的連接請求沒有收到Server的確認,於是一段時間后,client又重新向server發送方連接請求,且建立成功,順利完成數據傳輸。
考慮這樣一種特殊情況,client第一次發送的連接請求並沒有丟失,而是因為網絡節點導致延遲到達server,Server主機以為是client又發起的新請求連接,於是server同意連接,並向client發回確認,但是此時client根本不會理會,server就一直等待client發送數據,導致server資源浪費。
采用二次握手不行,原因就是上面說的失效的連接請求的特殊情況,因此采用三次握手剛剛好,兩次可能出實現失效,更多次則沒必要,反而復雜了。

為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最后一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

統計TCP連接每種狀態的連接的數量
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

zabbix ----監控TCP連接狀態

TCP的連接狀態可以看出網絡的連接情況,服務器的壓力情況,對服務器的並發有很好的直觀反映,

基本查詢命令:

[root@172-21-3-220 ~]# netstat -an|awk '/^tcp/{++S[$NF]}END{for(a in S) print a,S[a]}'
LISTEN 13
ESTABLISHED 26
TIME_WAIT 35

客戶端配置:

1)TCP狀態獲取腳本

# vim /etc/zabbix/scripts/tcp_conn_status.sh 
#!/bin/bash
#this script is used to get tcp and udp connetion status
#tcp status
metric=$1
tmp_file=/tmp/tcp_status.txt
/bin/netstat -an|awk '/^tcp/{++S[$NF]}END{for(a in S) print a,S[a]}' > $tmp_file
 
case $metric in
   closed)
          output=$(awk '/CLOSED/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   listen)
          output=$(awk '/LISTEN/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   synrecv)
          output=$(awk '/SYN_RECV/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   synsent)
          output=$(awk '/SYN_SENT/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   established)
          output=$(awk '/ESTABLISHED/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   timewait)
          output=$(awk '/TIME_WAIT/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   closing)
          output=$(awk '/CLOSING/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   closewait)
          output=$(awk '/CLOSE_WAIT/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
        ;;
   lastack)
          output=$(awk '/LAST_ACK/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
         ;;
   finwait1)
          output=$(awk '/FIN_WAIT1/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
         ;;
   finwait2)
          output=$(awk '/FIN_WAIT2/{print $2}' $tmp_file)
          if [ "$output" == "" ];then
             echo 0
          else
             echo $output
          fi
         ;;
         *)
          echo -e "\e[033mUsage: sh  $0 [closed|closing|closewait|synrecv|synsent|finwait1|finwait2|listen|established|lastack|timewait]\e[0m"
   
esac

2)給腳本賦予執行權限並執行腳本進行測試,給tcp_status.txt文本zabbix權限

# chmod +x /etc/zabbix/scripts/tcp_conn_status.sh

# bash /etc/zabbix/scripts/tcp_conn_status.sh established
1239
# chown zabbix.zabbix /tmp/tcp_status.txt

3)配置zabbix監控項鍵值

# vim /etc/zabbix/zabbix_agentd.d/userparameter_tcp_conn.conf
UserParameter=tcp.status[*],/etc/zabbix/scripts/tcp_conn_status.sh $1

4)重啟zabbix-agent

服務端配置:

獲取 監控模板

模板鏈接:https://pan.baidu.com/s/1pq-2Swff1XzeHwVkvABQEQ 提取碼:2iab

TCP連接參數調優

  1. 開啟SYN cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0表示關閉:
    net.ipv4.tcp_syncookies = 1
  2. 開啟重用。允許將TIME_WAIT sockets重新用於新的TCP連接,默認為0表示關閉:
    net.ipv4.tcp_tw_reuse = 1
  3. 開啟TCP連接中TIME_WAIT sockets的快速回收,默認為0表示關閉:
    net.ipv4.tcp_tw_recycle = 1
  4. 系統默認的TIMEOUT時間
    net.ipv4.tcp_fin_timeout = 5
  5. 當keepalive啟用的時候,TCP發送keepalived消息的頻度,默認是2h,改為20min:
    net.ipv4.tcp_keepalive_time = 1200
  6. 用於向外連接的端口范圍
    net.ipv4.ip_local_port_range = 32768 60999
  7. SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網絡連接數
    net.ipv4.tcp_max_syn_backlog = 8192
  8. 系統同時保持TIME_WAIT的最大數量,如果超過這個數字,TIME_WAIT將立刻被清除並打印警告信息
    net.ipv4.tcp_max_tw_buckets = 65536


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM