TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫爲 TCP)是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議,由IETF的RFC 793定義。服務器
TCP通訊須要通過建立鏈接、數據傳送、終止鏈接三個步驟。socket
TCP通訊是面向鏈接而且可靠的。通訊雙方在正式進行通訊以前必須先創建可靠一對一的鏈接,而且分配必定的系統內核資源,雙發的數據經過這個鏈接進行,並且當通訊結束以後雙發必須斷開鏈接以釋放系統資源。tcp
TCP採用發送應答機制,每次傳輸的成功都依賴於發送和迴應。若是在必定時間沒有收到迴應,則會進行重發。而且爲了避免丟包,每一個數據包中都有一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。spa
from socket import *
# 建立socket
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# 目的信息
server_ip = input("請輸入服務器ip:")
server_port = int(input("請輸入服務器port:"))
# 連接服務器
tcp_client_socket.connect((server_ip, server_port))
# 提示用戶輸入數據
send_data = input("請輸入要發送的數據:")
tcp_client_socket.send(send_data.encode("gbk"))
# 接收對方發送過來的數據,最大接收1024個字節
recvData = tcp_client_socket.recv(1024)
print('接收到的數據爲:', recvData.decode('gbk'))
# 關閉套接字
tcp_client_socket.close()
複製代碼
from socket import *
# 建立socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 本地信息
address = ('', 7890)
# 綁定
tcp_server_socket.bind(address)
# 使用socket建立的套接字默認的屬性是主動的,使用listen將其變爲被動的,這樣就能夠接收別人的連接了
tcp_server_socket.listen(128)
# 若是有新的客戶端來連接服務器,那麼就產生一個新的套接字專門爲這個客戶端服務
# client_socket用來爲這個客戶端服務
# tcp_server_socket就能夠省下來專門等待其餘新客戶端的連接
client_socket, clientAddr = tcp_server_socket.accept()
# 接收對方發送過來的數據
recv_data = client_socket.recv(1024) # 接收1024個字節
print('接收到的數據爲:', recv_data.decode('gbk'))
# 發送一些數據到客戶端
client_socket.send("thank you !".encode('gbk'))
# 關閉爲這個客戶端服務的套接字,只要關閉了,就意味着爲不能再爲這個客戶端服務了,若是還須要服務,只能再次從新鏈接
client_socket.close()
複製代碼
當客戶端要跟服務端通訊的時候會經過三次握手來進行資源的準備。code
下文中的SYN和ACK是爲了區分請求(SYN)和應答(ACK)。J、K僅表明隨機標識,實際並不會發送J、K。cdn
首先客戶端發起請求並將帶有帶有一個隨機標記SYN J的數據包給服務端。爲了標記響應在前面添加SYN。server
服務端接受到以後,revc會解堵塞,並分配一個新的套接字來對數據進行收發。因爲TCP要求每次請求都要有一次應答,因此服務端將客戶端發送過來的隨機標記加一 J+1發送給客戶端告訴它服務端已經準備好資源了。爲了標記響應在前面添加ACK。blog
此時服務端也須要確認客戶端是不是可靠的,同時客戶端也須要進行資源準備,因此服務端會向客戶端發送一個一樣帶有隨機標記的數據包(SYN K)。ip
當客戶端收到服務端的包的時候也須要給服務端發送確認的包,因此把服務端發送過來的K加一將(ACK K+1)發送給服務端。資源
因爲服務器應答和服務器確認客戶端都是發往客戶端的,而且中間不會有延時或者不發的狀況,因此服務端確認客戶端的包就跟服務端相應客戶端鏈接的包一塊兒發送給客戶端了。兩步合爲一步,因此叫三次握手。
當這三次握手完成以後雙方便確認對方是可靠的,就能夠進行通訊了。
當客戶端和服務端雙方通訊結束的時候,爲了保證系統資源的釋放,雙方須要經過四次揮手來斷開鏈接,釋放資源。因爲套接字socket是全雙工的,也就是收發能夠同時進行,因此當關閉一個套接字的時候須要關閉發送和接收兩個通道。
數據包的發送同三次握手同樣一樣會發送一個隨機標記,在響應的時候對其進行加一操做。
斷開鏈接一般也是由客戶端首先發起的,當客戶端的socket調用close關閉鏈接的時候會發送數據包給服務端。
服務端收到客戶端的數據包的時候會回覆給客戶端一個數據包,表示確認收到客戶端關閉鏈接的請求。
服務端的recv解堵塞,當服務端的套接字調用close的時候會給客戶端發送一個數據包通知客戶端將要關閉發送。可是此時服務端會保留資源,直到收到客戶端的確認包。
當客戶端接收到數據包的時候再給服務端發送確認包,此時客戶端的資源也會被保留一段時間。
正常狀況下,客戶端和服務端都會收到兩次響應,從而關閉socket的收發兩個通道。
服務端資源保留是由於若是到服務端TCP數據包發送的超時時間尚未收到客戶端的迴應,那麼會再次給客戶端發送數據包。而客戶端資源保留也是由於若是服務端沒有收到數據包的時候回再次發送過來數據,因此須要進行接收。若是是客戶端發起的關閉請求,那麼客戶端的資源一般會保留2msl也就是接受兩次數據包的時間,增長接收到服務端重發數據包的機率,若是過期也會關閉套接字釋放資源。
四次揮手中服務端發送給客戶端的關閉請求的響應和給客戶端發送確認關閉的數據包,沒有像三次握手那樣合爲一塊兒,是由於服務端調用close的時機不肯定,而若是是客戶端先發起的close,那麼客戶端就要等待兩倍的數據包發送時長。服務端是綁定端口的,若是沒有釋放資源是不能再次進行服務的,而客戶端是隨機端口的,不會受此限制。
經過TCP進行通訊的時候首先經過三次握手準備資源,而後進行通訊。通訊過程也是有來有回的,每次請求都會對應一次響應。當通訊結束的時候,會經過四次揮手關閉鏈接,釋放系統資源。