10-三次握手四次揮手
三次握手
[root@Rocky ~]# ethtool ens33
Link detected: yes #埠正常
[root@Rocky ~]# rpm -ql netcat
/usr/bin/nc
ss -nutlp #檢視tcp udp連結埠和程序對應關係來自於iproute包,代替netstat,netstat 通過遍歷 /proc來獲取 socket資訊,ss 使用 netlink與核心tcp_diag 模組通訊獲取 socket 資訊
-t: tcp協議相關 -u: udp協議相關 -w: 裸套接字相關 -x:unix sock相關 -l: listen狀態的連線傳輸層通過port號,確定應用層協議,範圍0-65535-a: 所有 -n: 數字格式 -p: 相關的程式及PID -e: 擴充套件的資訊 -m:記憶體用量 -o:計時器資訊
wang@ubuntu2004:~$ nc -l 1023 nc: Permission denied
0-1023:系統埠或特權埠(僅管理員可用) ,眾所周知,永久的分配給固定的系統應用使用, 22/tcp(ssh), 80/tcp(http), 443/tcp(https) 1024-49151:使用者埠或註冊埠,但要求並不嚴格,分配給程式註冊為某應用使用, 1433/tcp(SqlServer), 1521/tcp(oracle),3306/tcp(mysql),11211/tcp/udp (memcached) 49152-65535:動態或私有埠,客戶端隨機使用埠,範圍定 義:/proc/sys/net/ipv4/ip_local_port_range 注意:當前6000,6665-6669/tcp等埠被Google Chrome 設為預設非安全埠,儘量避免使用 範例: 檢視非特權使用者可以使用起始埠
[root@Rocky yum.repos.d]# cat /proc/sys/net/ipv4/ip_unprivileged_port_start 1024範例:調整客戶端的動態埠範圍
[root@Rocky ~]# cat /proc/sys/net/ipv4/ip_local_port_range20000 62000
監聽22埠
[root@Rocky ~]# nc -l 222 ss -tnl LISTEN 0 10 [::]:222
root@ubuntu2004:/etc/apt# nc 192.168.80.171 222
[root@Rocky ~]# ss -nt State Recv-Q Send-Q Local Address:Port Peer Address:Port Process CLOSE-WAIT 32 0 192.168.80.171:44172 8.43.85.13:443 ESTAB 0 52 192.168.80.171:22 192.168.80.1:50060 ESTAB 0 0 192.168.80.171:222 192.168.80.181:50882 #遠端計算機socket
root@ubuntu2004:/etc/apt# nc 192.168.80.171 222 I am ubuntu
ip.src == 192.168.80.171 and ip.dst==192.168.80.181
[root@Rocky ~]# ss -nt State Recv-Q Send-Q Local Address:Port Peer Address:Port Process CLOSE-WAIT 32 0 192.168.80.171:44172 8.43.85.13:443 ESTAB 0 52 192.168.80.171:22 192.168.80.1:50060
root@ubuntu2004:~# ss -nt State Recv-Q Send-Q Local Address:Port Peer Address:Port Process ESTAB 0 36 192.168.80.181:22 192.168.80.1:50065 CLOSE-WAIT 0 0 192.168.80.181:50882 192.168.80.171:222
tcpdump -n -t -S -i ens33 port 3334 -w tcp3.cap
-i : 指定抓包的網絡卡是enp0s3 -n: 把域名轉成IP顯示 -t: 不顯示時間 -S: 序列號使用絕對數值,不指定-S的話,序列號會使用相對的數值 port: 指定監聽埠是80 host:指定監聽的主機名
三系握手過程
第一次握手:
客戶端將TCP報文標誌位SYN置為1,隨機產生一個序號值seq=J,儲存在TCP首部的序列號(Sequence Number)欄位裡,指明客戶端打算連線的伺服器的埠,並將該資料包傳送給伺服器端,傳送完畢後,客戶端進入SYN_SENT
狀態,等待伺服器端確認。
第二次握手:
伺服器端收到資料包後由標誌位SYN=1知道客戶端請求建立連線,伺服器端將TCP報文標誌位SYN和ACK都置為1,ack=J+1,隨機產生一個序號值seq=K,並將該資料包傳送給客戶端以確認連線請求,伺服器端進入SYN_RCVD
狀態。
第三次握手:
客戶端收到確認後,檢查ack是否為J+1,ACK是否為1,如果正確則將標誌位ACK置為1,ack=K+1,並將該資料包傳送給伺服器端,伺服器端檢查ack是否為K+1,ACK是否為1,如果正確則連線建立成功,客戶端和伺服器端進入ESTABLISHED
狀態,完成三次握手,隨後客戶端與伺服器端之間可以開始傳輸資料了。
為什麼需要三次握手?
我們假設client發出的第一個連線請求報文段並沒有丟失,而是在某個網路結點長時間的滯留了,以致延誤到連線釋放以後的某個時間才到達server。
本來這是一個早已失效的報文段。但server收到此失效的連線請求報文段後,就誤認為是client再次發出的一個新的連線請求。於是就向client發出確認報文段,同意建立連線。
假設不採用“三次握手”,那麼只要server發出確認,新的連線就建立了。由於現在client並沒有發出建立連線的請求,因此不會理睬server的確認,也不會向server傳送資料。但server卻以為新的運輸連線已經建立,並一直等待client發來資料。這樣,server的很多資源就白白浪費掉了。
所以,採用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連線。
TCP 四次揮手關閉連線
由客戶端或服務端任一方執行close來觸發。
由於TCP連線是全雙工的,因此,每個方向都必須要單獨進行關閉,這一原則是當一方完成資料傳送任務後,傳送一個FIN來終止這一方向的連線,收到一個FIN只是意味著這一方向上沒有資料流動了,即不會再收到資料了,但是在這個TCP連線上仍然能夠傳送資料,直到這一方向也傳送了FIN。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉。
四次揮手過程的示意圖如下:
揮手請求可以是Client端,也可以是Server端發起的,我們假設是Client端發起:
-
第一次揮手: Client端發起揮手請求,向Server端傳送標誌位是FIN報文段,設定序列號seq,此時,Client端進入
FIN_WAIT_1
狀態,這表示Client端沒有資料要傳送給Server端了。 -
第二次分手:Server端收到了Client端傳送的FIN報文段,向Client端返回一個標誌位是ACK的報文段,ack設為seq加1,Client端進入
FIN_WAIT_2
狀態,Server端告訴Client端,我確認並同意你的關閉請求。 -
第三次分手: Server端向Client端傳送標誌位是FIN的報文段,請求關閉連線,同時Client端進入
LAST_ACK
狀態。 -
第四次分手 : Client端收到Server端傳送的FIN報文段,向Server端傳送標誌位是ACK的報文段,然後Client端進入
TIME_WAIT
狀態。Server端收到Client端的ACK報文段以後,就關閉連線。此時,Client端等待2MSL的時間後依然沒有收到回覆,則證明Server端已正常關閉,那好,Client端也可以關閉連線了。
為什麼連線的時候是三次握手,關閉的時候卻是四次握手?
建立連線時因為當Server端收到Client端的SYN連線請求報文後,可以直接傳送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。所以建立連線只需要三次握手。
由於TCP協議是一種面向連線的、可靠的、基於位元組流的運輸層通訊協議,TCP是全雙工模式。
這就意味著,關閉連線時,當Client端發出FIN報文段時,只是表示Client端告訴Server端資料已經發送完畢了。當Server端收到FIN報文並返回ACK報文段,表示它已經知道Client端沒有資料傳送了,但是Server端還是可以傳送資料到Client端的,所以Server很可能並不會立即關閉SOCKET,直到Server端把資料也傳送完畢。
當Server端也傳送了FIN報文段時,這個時候就表示Server端也沒有資料要傳送了,就會告訴Client端,我也沒有資料要傳送了,之後彼此就會愉快的中斷這次TCP連線。
為什麼要等待2MSL?
MSL:報文段最大生存時間,它是任何報文段被丟棄前在網路內的最長時間。
有以下兩個原因:
第一點:保證TCP協議的全雙工連線能夠可靠關閉:
由於IP協議的不可靠性或者是其它網路原因,導致了Server端沒有收到Client端的ACK報文,那麼Server端就會在超時之後重新發送FIN,如果此時Client端的連線已經關閉處於CLOESD
狀態,那麼重發的FIN就找不到對應的連線了,從而導致連線錯亂,所以,Client端傳送完最後的ACK不能直接進入CLOSED
狀態,而要保持TIME_WAIT
,當再次收到FIN的收,能夠保證對方收到ACK,最後正確關閉連線。
第二點:保證這次連線的重複資料段從網路中消失
如果Client端傳送最後的ACK直接進入CLOSED
狀態,然後又再向Server端發起一個新連線,這時不能保證新連線的與剛關閉的連線的埠號是不同的,也就是新連線和老連線的埠號可能一樣了,那麼就可能出現問題:如果前一次的連線某些資料滯留在網路中,這些延遲資料在建立新連線後到達Client端,由於新老連線的埠號和IP都一樣,TCP協議就認為延遲資料是屬於新連線的,新連線就會接收到髒資料,這樣就會導致資料包混亂。所以TCP連線需要在TIME_WAIT狀態等待2倍MSL,才能保證本次連線的所有資料在網路中消失。