TCP的三次握手和四次揮手簡(jiǎn)述

原文https://juejin.im/post/5cf671e4e51d45590a445b00

TCP協(xié)議,傳輸控制協(xié)議(英語:Transmission Control Protocol,縮寫為 TCP)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,由IETF的RFC 793定義。

TCP

TCP通信需要經(jīng)過創(chuàng)建連接、數(shù)據(jù)傳送、終止連接三個(gè)步驟。

TCP通信是面向連接并且可靠的。通信雙方在正式進(jìn)行通信之前必須先建立可靠一對(duì)一的連接,并且分配一定的系統(tǒng)內(nèi)核資源,雙發(fā)的數(shù)據(jù)通過這個(gè)連接進(jìn)行,而且當(dāng)通信結(jié)束之后雙發(fā)必須斷開連接以釋放系統(tǒng)資源。

TCP采用發(fā)送應(yīng)答機(jī)制,每次傳輸?shù)某晒Χ家蕾囉诎l(fā)送和回應(yīng)。如果在一定時(shí)間沒有收到回應(yīng),則會(huì)進(jìn)行重發(fā)。并且為了不丟包,每個(gè)數(shù)據(jù)包中都有一個(gè)序號(hào),同時(shí)序號(hào)也保證了傳送到接收端實(shí)體的包的按序接收。

TCP客戶端的實(shí)現(xiàn)代碼:

from socket import *

# 創(chuàng)建socket
tcp_client_socket = socket(AF_INET, SOCK_STREAM)

# 目的信息
server_ip = input("請(qǐng)輸入服務(wù)器ip:")
server_port = int(input("請(qǐng)輸入服務(wù)器port:"))

# 鏈接服務(wù)器
tcp_client_socket.connect((server_ip, server_port))

# 提示用戶輸入數(shù)據(jù)
send_data = input("請(qǐng)輸入要發(fā)送的數(shù)據(jù):")

tcp_client_socket.send(send_data.encode("gbk"))

# 接收對(duì)方發(fā)送過來的數(shù)據(jù),最大接收1024個(gè)字節(jié)
recvData = tcp_client_socket.recv(1024)
print('接收到的數(shù)據(jù)為:', recvData.decode('gbk'))

# 關(guān)閉套接字
tcp_client_socket.close()
復(fù)制代碼

TCP的服務(wù)端代碼:

from socket import *

# 創(chuàng)建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)

# 本地信息
address = ('', 7890)

# 綁定
tcp_server_socket.bind(address)

# 使用socket創(chuàng)建的套接字默認(rèn)的屬性是主動(dòng)的,使用listen將其變?yōu)楸粍?dòng)的,這樣就可以接收別人的鏈接了
tcp_server_socket.listen(128)

# 如果有新的客戶端來鏈接服務(wù)器,那么就產(chǎn)生一個(gè)新的套接字專門為這個(gè)客戶端服務(wù)
# client_socket用來為這個(gè)客戶端服務(wù)
# tcp_server_socket就可以省下來專門等待其他新客戶端的鏈接
client_socket, clientAddr = tcp_server_socket.accept()

# 接收對(duì)方發(fā)送過來的數(shù)據(jù)
recv_data = client_socket.recv(1024)  # 接收1024個(gè)字節(jié)
print('接收到的數(shù)據(jù)為:', recv_data.decode('gbk'))

# 發(fā)送一些數(shù)據(jù)到客戶端
client_socket.send("thank you !".encode('gbk'))

# 關(guān)閉為這個(gè)客戶端服務(wù)的套接字,只要關(guān)閉了,就意味著為不能再為這個(gè)客戶端服務(wù)了,如果還需要服務(wù),只能再次重新連接
client_socket.close()
復(fù)制代碼

TCP的三次握手

image.png

當(dāng)客戶端要跟服務(wù)端通信的時(shí)候會(huì)通過三次握手來進(jìn)行資源的準(zhǔn)備。

下文中的SYN和ACK是為了區(qū)分請(qǐng)求(SYN)和應(yīng)答(ACK)。J、K僅代表隨機(jī)標(biāo)識(shí),實(shí)際并不會(huì)發(fā)送J、K。

  1. 首先客戶端發(fā)起請(qǐng)求并將帶有帶有一個(gè)隨機(jī)標(biāo)記SYN J的數(shù)據(jù)包給服務(wù)端。為了標(biāo)記響應(yīng)在前面添加SYN。

  2. 服務(wù)端接受到之后,revc會(huì)解堵塞,并分配一個(gè)新的套接字來對(duì)數(shù)據(jù)進(jìn)行收發(fā)。由于TCP要求每次請(qǐng)求都要有一次應(yīng)答,所以服務(wù)端將客戶端發(fā)送過來的隨機(jī)標(biāo)記加一 J+1發(fā)送給客戶端告訴它服務(wù)端已經(jīng)準(zhǔn)備好資源了。為了標(biāo)記響應(yīng)在前面添加ACK。

  3. 此時(shí)服務(wù)端也需要確認(rèn)客戶端是否是可靠的,同時(shí)客戶端也需要進(jìn)行資源準(zhǔn)備,所以服務(wù)端會(huì)向客戶端發(fā)送一個(gè)同樣帶有隨機(jī)標(biāo)記的數(shù)據(jù)包(SYN K)。

  4. 當(dāng)客戶端收到服務(wù)端的包的時(shí)候也需要給服務(wù)端發(fā)送確認(rèn)的包,所以把服務(wù)端發(fā)送過來的K加一將(ACK K+1)發(fā)送給服務(wù)端。

由于服務(wù)器應(yīng)答和服務(wù)器確認(rèn)客戶端都是發(fā)往客戶端的,并且中間不會(huì)有延時(shí)或者不發(fā)的情況,所以服務(wù)端確認(rèn)客戶端的包就跟服務(wù)端相應(yīng)客戶端連接的包一起發(fā)送給客戶端了。兩步合為一步,所以叫三次握手。

當(dāng)這三次握手完成之后雙方便確認(rèn)對(duì)方是可靠的,就可以進(jìn)行通信了。

TCP四次揮手

image.png

當(dāng)客戶端和服務(wù)端雙方通信結(jié)束的時(shí)候,為了保證系統(tǒng)資源的釋放,雙方需要通過四次揮手來斷開連接,釋放資源。由于套接字socket是全雙工的,也就是收發(fā)可以同時(shí)進(jìn)行,所以當(dāng)關(guān)閉一個(gè)套接字的時(shí)候需要關(guān)閉發(fā)送和接收兩個(gè)通道。

數(shù)據(jù)包的發(fā)送同三次握手一樣同樣會(huì)發(fā)送一個(gè)隨機(jī)標(biāo)記,在響應(yīng)的時(shí)候?qū)ζ溥M(jìn)行加一操作。

  1. 斷開連接通常也是由客戶端首先發(fā)起的,當(dāng)客戶端的socket調(diào)用close關(guān)閉連接的時(shí)候會(huì)發(fā)送數(shù)據(jù)包給服務(wù)端。

  2. 服務(wù)端收到客戶端的數(shù)據(jù)包的時(shí)候會(huì)回復(fù)給客戶端一個(gè)數(shù)據(jù)包,表示確認(rèn)收到客戶端關(guān)閉連接的請(qǐng)求。

  3. 服務(wù)端的recv解堵塞,當(dāng)服務(wù)端的套接字調(diào)用close的時(shí)候會(huì)給客戶端發(fā)送一個(gè)數(shù)據(jù)包通知客戶端將要關(guān)閉發(fā)送。但是此時(shí)服務(wù)端會(huì)保留資源,直到收到客戶端的確認(rèn)包。

  4. 當(dāng)客戶端接收到數(shù)據(jù)包的時(shí)候再給服務(wù)端發(fā)送確認(rèn)包,此時(shí)客戶端的資源也會(huì)被保留一段時(shí)間。

正常情況下,客戶端和服務(wù)端都會(huì)收到兩次響應(yīng),從而關(guān)閉socket的收發(fā)兩個(gè)通道。

服務(wù)端資源保留是因?yàn)槿绻椒?wù)端TCP數(shù)據(jù)包發(fā)送的超時(shí)時(shí)間還沒有收到客戶端的回應(yīng),那么會(huì)再次給客戶端發(fā)送數(shù)據(jù)包。而客戶端資源保留也是因?yàn)槿绻?wù)端沒有收到數(shù)據(jù)包的時(shí)候回再次發(fā)送過來數(shù)據(jù),所以需要進(jìn)行接收。如果是客戶端發(fā)起的關(guān)閉請(qǐng)求,那么客戶端的資源通常會(huì)保留2msl也就是接受兩次數(shù)據(jù)包的時(shí)間,增加接收到服務(wù)端重發(fā)數(shù)據(jù)包的概率,如果過時(shí)也會(huì)關(guān)閉套接字釋放資源。

四次揮手中服務(wù)端發(fā)送給客戶端的關(guān)閉請(qǐng)求的響應(yīng)和給客戶端發(fā)送確認(rèn)關(guān)閉的數(shù)據(jù)包,沒有像三次握手那樣合為一起,是因?yàn)榉?wù)端調(diào)用close的時(shí)機(jī)不確定,而如果是客戶端先發(fā)起的close,那么客戶端就要等待兩倍的數(shù)據(jù)包發(fā)送時(shí)長(zhǎng)。服務(wù)端是綁定端口的,如果沒有釋放資源是不能再次進(jìn)行服務(wù)的,而客戶端是隨機(jī)端口的,不會(huì)受此限制。

總結(jié)

通過TCP進(jìn)行通信的時(shí)候首先通過三次握手準(zhǔn)備資源,然后進(jìn)行通信。通信過程也是有來有回的,每次請(qǐng)求都會(huì)對(duì)應(yīng)一次響應(yīng)。當(dāng)通信結(jié)束的時(shí)候,會(huì)通過四次揮手關(guān)閉連接,釋放系統(tǒng)資源。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容