使用wireshark抓包讀懂tcp三次握手,四次揮手

tcp三次握手和四次揮手的描述不少,可是感受大部分文章看下來很難具象化這個過程,下面使用這個wireshark抓包工具,經過抓取到的數據包來理解一下,可以從另外一個角度理解tcp三次握手了html

完整案例代碼已上傳github: github.com/neatlife/my…java

wireshark下載地址:www.wireshark.org/download.ht…git

建立案例項目

能夠在idea中建立一個maven項目,建立用來測試3次握手和4次揮手的兩個模塊,建立模塊在idea右鍵菜單裏就有: github

把握手和揮手分開測試是爲了防止客戶端在發送過程當中,服務端就提早關閉了,而後揮手的部分包可能會丟掉,這個丟包的效果能夠自行嘗試shell

編寫握手客戶端和服務端

服務端

創建一個socket服務器,並在8881端口上監聽,核心代碼以下:編程

ServerSocket socket = new ServerSocket(8881);
socket.accept();
TimeUnit.SECONDS.sleep(2);
socket.close();
複製代碼

客戶端

鏈接上面的服務器,併發送幾回數據,每次發送幾個字節的數據,核心代碼以下:服務器

Socket socket = new Socket("127.0.0.1", 8881);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("111".getBytes());
outputStream.write("1111l".getBytes());
outputStream.write("11111l111l".getBytes());
socket.close();
複製代碼

編寫揮手客戶端和服務端

服務端

核心代碼以下:微信

ServerSocket serverSocket = new ServerSocket(8881);
Socket socket = serverSocket.accept();
socket.close();
serverSocket.close();
複製代碼

客戶端

核心代碼以下:併發

Socket socket = new Socket("127.0.0.1", 8881);
socket.close();
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
複製代碼

編寫wireshark捕獲過濾器

wireshark抓的包已經上傳到github,能夠直接使用wireshark打開案例項目裏的握手包:handshake.pcapng,和揮手包:wave.pcapngsocket

捕獲過濾器以下:

host 127.0.0.1 and port 8881
複製代碼

填寫到wireshark中:

啓動抓包

抓取的握手的包

運行握手模塊的服務端和客戶端,查看wireshark抓到的包

右鍵新窗口能夠查看大圖

注意上面這個[TCP Window Update]包能夠忽略,這個包是服務端用來控制客戶端發送包的頻率的,這個包不必定會有,具體能夠參考TCP傳輸協議抓包經驗

抓取揮手的包

分析抓到的包

預備知識: 要看懂上面wireshark抓的包,下面的這個指令須要提早了解下

標誌位 做用
SYN 表示請求創建鏈接
FIN 表示請求斷開鏈接
Seq 表示曾經發送過數據的字節數+1,0表示以前沒有發送過數據
Len 本次收到的數據字節大小,0表示本次沒有收到數據
ACK 表示對對方過來的請求的確認
Ack 表示期待下次對方發送過來的Seq指令的值

注意:

  1. 即便Seq不爲0,並不表示曾經必定發送過數據,是否發送過數據須要依據Len指令的值有沒有大於0的來判斷。
  2. 3次握手和4次揮手過程當中通常是不會傳送數據的,因此這個過程當中Len指令都是0

經微信讀者「R.飛」指正,4次揮手過程當中是能夠傳數據的(未驗證,有興趣的讀者能夠自行驗證)

經微信讀者「ヤキモチ」指正,3次握手過程當中的第三次握手也能夠傳數據的(未驗證,有興趣的讀者能夠自行驗證)

怎麼確認握手有3次

握手過程當中沒有隻有指令交互,沒有數據交互,因此開始的Len=0的全部交互都屬於握手,效果以下

經過這個圖,能夠得出如下結論

  1. 客戶端發送了兩次請求到服務端,服務端發送了一次請求到客戶端
  2. 第一次握手是客戶端請求服務端,發送的syn指令表示客戶端想要和服務端創建鏈接
  3. 第二次握手是服務端收到客戶端發送的syn指令後,給客戶端發送的ack指令,表示接受客戶端想要創建鏈接的請求,同時服務端也給客戶端發送了syn指令,表示服務端請求想要和客戶端創建鏈接
  4. 第三次握手是客戶端知道了服務端贊成鏈接了,而且也想發送數據給客戶端,客戶端迴應一個ack,表示容許服務端給客戶端發送數據

怎麼確認揮手有4次

握手過程當中沒有隻有指令交互,沒有數據交互,經過這個特性,從後往前數,找到全部Len=0的包便可,能夠看到,只有4個這樣的包

經過上面這個圖,能夠得出如下結論

  1. 客戶端發送了兩次請求到服務端,服務端發送了兩次請求到客戶端
  2. 揮手首先是客戶端發起的
  3. 第一次揮手是客戶端向服務端請求想要斷開鏈接(FIN指令)
  4. 第二次揮手是服務端收到客戶端的請求,併發送能夠斷開了的確認消息給客戶端(ACK指令)
  5. 第三次揮手是服務端向客戶端請求想要斷開鏈接(FIN)
  6. 第四次揮手是客戶端收到服務端的請求,併發送能夠斷開了的確認消息給服務端(ACK)

一些注意的點

即便這是個簡單的分析也參考了一些資料

  1. TCP傳輸協議抓包經驗
  2. <<NIO與Socket編程技術指南 (Java核心技術系列)>>
  3. <<TCP/IP詳解·卷1:協議(原書第2版)>>

ACK和Ack做用是不一樣的,ACK表示確認收到了數據,Ack表示下一次發過來的數據的序號

若是idea沒法識別子模塊中的java文件,可能須要從新import下模塊的pom.xml

若是在操做過程當中遇到問題,可加做者微信探討

wx
相關文章
相關標籤/搜索