【摘要】本文重點分析計算機網絡中TCP協議中的握手和揮手的過程。
【前提說明】
前段時間突然看到了一篇關於TCP/IP模型的文章,心想這段時間在家里也用wireshark抓了點包,那么想着想着就覺得需要復習一下網絡知識,於是就有這篇博文的誕生。當然網上關於TCP相關的知識點也是芸芸,閑着無事也可以多google深入理解一下,本文重點在分析TCP協議中的握手和揮手的過程。
【抓包前准備】
既然要抓包,我的裝備是個人電腦,操作系統是Mac OS。抓包工具是wireshark,至於怎么安裝和一些基本的操作,可以點擊參考這篇文章。
用本地電腦模擬server和client,都是localhost的地址,但是我選擇的是不同的端口進行標識。server的端口號:12345;client的端口號:50784。因為是用的本機做的實驗,所以wireshark監聽的不是網卡而是Loopback:lo0,如圖所示:
以下是我模擬client和server的代碼:
1)server端
-Python 代碼 01 #! /usr/bin/python 02 # -*- coding: utf-8 -*- 03 04 import socket 05 06 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 07 08 server_address = ('127.0.0.1', 12345) 09 print "Starting up on %s:%s" % server_address 10 sock.bind(server_address) 11 12 sock.listen(1) 13 14 while True: 15 print "Waiting for a connection" 16 connection, client_address = sock.accept() 17 18 try: 19 print "Connection from", client_address 20 21 data = connection.recv(1024) 22 print "Receive '%s'" % data 23 finally: 24 connection.close()
2)client端-Python 代碼
01 # /usr/bin/python 02 # -*- coding: utf-8 -*- 03 04 import socket 05 06 def check_tcp_status(ip, port): 07 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 08 09 server_address = (ip, port) 10 print 'Connecting to %s:%s.' % server_address 11 sock.connect(server_address) 12 13 message = "I'm TCP client" 14 print 'Sending "%s".' % message 15 sock.sendall(message) 16 17 print 'Closing socket.' 18 sock.close() 19 20 21 if __name__ == "__main__": 22 print check_tcp_status("127.0.0.1", 12345)
代碼比較簡單,就是模擬了一次鏈接,可以多次執行client,client只要鏈接成功就會發送一句話“I'm TCP client”,server一直死循環監聽端口,並將接受到的信息打印到console中。
【結果分析】
看到上面的console輸出之后,我們看一下wireshark抓到的結果:
我用兩種顏色標了出來,可以看到黃色框中的序號為1、2、3的三次通信過程其實就是我們說的三次握手;握手建立之后的序號為4、5、6便為傳輸數據的過程;而序號7、8、9、10就是我們所說的四次揮手的過程。
我們再進一步細看下握手、揮手這倆過程。
三次握手
我們來總結一下握手的規律:
- 第一次握手:建立鏈接。客戶端發送鏈接的請求,發送SYN報文,將Seq設置為0。然后客戶端就進入了SYN_SEND狀態,等待服務器的確認。
- 第二次握手:服務器收到客戶端的SYN報文段。需要對這個SYN報文段進行確認,發送ACK報文,並將Ack設置為1。同時,自己也要發送SYN請求信息,將Seq設置為0,。服務器將上述的所有信息一並發送給客戶端,此時服務器進入SYN_RECV狀態。
- 第三次握手:客戶端收到服務器的ACK和SYN報文后,進行確認,然后將Ack設置為1,Seq設置為1,向服務器發送ACK報文段,這個報文段發送完畢之后,客戶端和服務器都進入了ESTABLISHED狀態。就此完成了TCP的三次握手。
四次揮手
接着總結下揮手的規律:
- 第一次揮手:客戶端想服務器發送一個FIN報文段,將設置Seq為15和Ack為1。此時客戶端進入FIN_WAIT_1狀態。這表示客戶端沒有數據要發送服務器了,請求關閉連接。
- 第二次揮手:服務器收到了客戶端發送的FIN報文段,向客戶端回一個ACK報文段,Ack設置為16,Seq設置為1;服務器進入了CLOSE_WAIT狀態,客戶端收到服務器返回的ACK報文之后隨即進入FIN_WAIT_2狀態。
- 第三次揮手:服務器會觀察自己是否還有數據沒有發送給客戶端,如果有,先把數據發送給客戶端,再發送FIN報文;如果沒有,那么服務器直接發送FIN報文給客戶端。請求關閉連接,同時服務器進入LAST_ACK狀態。
- 第四次揮手:客戶端收到服務器發送的FIN報文,向服務器發送ACK報文,將Seq設置為16,Ack設置為2,然后客戶端進入TIME_WAIT狀態;服務器收到客戶端的ACK報文之后就關閉了連接;此時,客戶端等待2msl后依然沒有收到回復,則證明服務器已正常關閉,客戶端也可以關閉連接了。
注意個規律: 每次一方返回ACK報文的時候,設置Ack=對方傳來的Seq值+1。
【理解TCP/IP模型】
說完TCP協議之后,不能免俗的要聊一下TCP/IP協議模型,該模型是計算機網絡的經典的模型了。該模型由OSI模型演化而來,由原來的7層簡化為了5層,具體如下圖所示:
TCP/IP協議被稱為傳輸控制協議/互聯網協議,又稱網絡通訊協議(Transmission Control Protocol)。是由網絡層的IP協議和傳輸層的TCP協議組成,是一個很大的協議集合。
- 物理層和數據鏈路層沒有定義任何特定協議,支持所有的標准和專用的協議。
- 網絡層定義了網絡互聯也就是IP協議,主要包括IP、ARP、RARP、ICMP、IGMP。
- 傳輸層定義了TCP和UDP(User Datagram Protocol),我們會后面重點介紹一下TCP協議。
- 應用層定義了HTTP(超文本傳輸協議)、FTP(文件傳輸協議)、DNS(域名系統)等協議。
TCP/IP的網絡模型分層思想算是非常有借鑒性的系統分層思想。映射到我們的軟件系統上來看,其實我們的軟件系統更多的時候也需要考慮分層,層次之間通過接口來交互。在嚴格的分層系統里,內部的層只對相鄰的層次可見,這樣就可以將一個復雜問題分解成增量步驟序列。由於每一層最多只影響兩層,也給維護帶來了很大的便利。
參考資料:
http://www.cnblogs.com/linyfeng/p/9496126.html
http://zhuanlan.zhihu.com/p/33797520
blog.csdn.net/zhzdeng/article/details/53490386