一、TCP簡介 TCP介紹 TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫為 TCP)是一種面向連接的、可靠的、基於位元組流的傳輸層通信協議,由IETF的RFC 793定義。 TCP通信需要經過創建連接、數據傳送、終止連接三個步驟。 TCP通信模型中, ...
一、TCP簡介
TCP介紹
TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫為 TCP)是一種面向連接的、可靠的、基於位元組流的傳輸層通信協議,由IETF的RFC 793定義。
TCP通信需要經過創建連接、數據傳送、終止連接三個步驟。
TCP通信模型中,在通信開始之前,一定要先建立相關的鏈接,才能發送數據,類似於生活中,"打電話"。
TCP特點
1. 面向連接
通信雙方必須先建立連接才能進行數據的傳輸,雙方都必須為該連接分配必要的系統內核資源,以管理連接的狀態和連接上的傳輸。
雙方間的數據傳輸都可以通過這一個連接進行。
完成數據交換後,雙方必須斷開此連接,以釋放系統資源。
這種連接是一對一的,因此TCP不適用於廣播的應用程式,基於廣播的應用程式請使用UDP協議。
2. 可靠傳輸
1)TCP採用發送應答機制
TCP發送的每個報文段都必須得到接收方的應答才認為這個TCP報文段傳輸成功
2)超時重傳
發送端發出一個報文段之後就啟動定時器,如果在定時時間內沒有收到應答就重新發送這個報文段。
TCP為了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認(ACK);如果發送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的數據包就被假設為已丟失將會被進行重傳。
3)錯誤校驗
TCP用一個校驗和函數來檢驗數據是否有錯誤;在發送和接收時都要計算校驗和。
4) 流量控制和阻塞管理
流量控制用來避免主機發送得過快而使接收方來不及完全收下。
TCP與UDP的不同點
-
面向連接(確認有創建三方交握,連接已創建才作傳輸。)
-
有序數據傳輸
-
重發丟失的數據包
-
捨棄重覆的數據包
-
無差錯的數據傳輸
-
阻塞/流量控制
udp通信模型
udp通信模型中,在通信開始之前,不需要建立相關的鏈接,只需要發送數據即可,類似於生活中,"寫信""
TCP通信模型
udp通信模型中,在通信開始之前,一定要先建立相關的鏈接,才能發送數據,類似於生活中,"打電話""
二、tcp網路程式-客戶端
tcp客戶端
tcp客戶端,並不是像之前一個段子:一個顧客去飯館吃飯,這個顧客要點菜,就問服務員咱們飯店有客戶端麽,然後這個服務員非常客氣的說道:先生 我們飯店不用客戶端,我們直接送到您的餐桌上
如果,不學習網路的知識是不是 說不定也會發生那樣的笑話 ,哈哈
所謂的伺服器端:就是提供服務的一方,而客戶端,就是需要被服務的一方
tcp客戶端構建流程
tcp的客戶端要比伺服器端簡單很多,如果說伺服器端是需要自己買手機、查手機卡、設置鈴聲、等待別人打電話流程的話,那麼客戶端就只需要找一個電話亭,拿起電話撥打即可,流程要少很多
示例代碼:
from socket import *
# 創建套接字
tcp_client_socket = socket(AD_INET, SOCK_STREAM)
# 目的地址
server_ip = input("服務端ip:")
server_port = input("服務端埠:")
# 鏈接伺服器
tcp_client_socket.connect((server_ip, int(server_port)))
# 客戶端發送信息
send_data = input("輸入發送的信息:")
tcp_client_socket.send(send_data.encode('utf-8'))
# 接受服務端發來的信息
recv_data = tcp_client_socket.recv(1024)
print("收到的信息:%s" % recv_data.decode('utf-8'))
# 關閉套接字
tcp_client_socket.close()
三、tcp網路程式-伺服器
tcp伺服器
生活中的電話機
如果想讓別人能更夠打通咱們的電話獲取相應服務的話,需要做以下幾件事情:
-
買個手機
-
插上手機卡
-
設計手機為正常接聽狀態(即能夠響鈴)
-
靜靜的等著別人撥打
tcp伺服器
如同上面的電話機過程一樣,在程式中,如果想要完成一個tcp伺服器的功能,需要的流程如下:
-
socket創建一個套接字
-
bind綁定ip和port
-
listen使套接字變為可以被動鏈接
-
accept等待客戶端的鏈接
-
recv/send接收發送數據
一個很簡單的tcp伺服器如下:
from socket import *
# 創建套接字
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 綁定地址
tcp_server_socket.bind(('192.168.1.1', 8001))
# 使用socket創建的套接字預設的屬性是主動的,使用listen將其變為被動的,這樣就
可以接收別人的鏈接了
tcp_server_socket.listen(128)
# 如果有新的客戶端來鏈接伺服器,那麼就產生一個新的套接字專門為這個客戶端服務
# client_socket用來為這個客戶端服務
# tcp_server_socket就可以省下來專門等待其他新客戶端的鏈接
client_socket, client_addr = tcp_server_socket.accept()
# 接受對方發來的消息
recv_data = client_socket.recv(1024)
print("收到的消息:%s" % recv_data.decode('utf-8'))
# 回覆對方消息
send_data = input("回覆消息:")
client_socket.send(send_data.encode('utf-8'))
# 關閉為這個客戶端服務的套接字,只要關閉了,就意味著為不能再為這個客戶端服務
了,如果還需要服務,只能再次重新連接
client_socket.close()
# 關閉伺服器的套接字
tcp_server_socket.close()
tcp註意點
-
tcp伺服器一般情況下都需要綁定,否則客戶端找不到這個伺服器
-
tcp客戶端一般不綁定,因為是主動鏈接伺服器,所以只要確定好伺服器的ip、port等信息就好,本地客戶端可以隨機
-
tcp伺服器中通過listen可以將socket創建出來的主動套接字變為被動的,這是做tcp伺服器時必須要做的
-
當客戶端需要鏈接伺服器時,就需要使用connect進行鏈接,udp是不需要鏈接的而是直接發送,但是tcp必須先鏈接,只有鏈接成功才能通信
-
當一個tcp客戶端連接伺服器時,伺服器端會有1個新的套接字,這個套接字用來標記這個客戶端,單獨為這個客戶端服務
-
listen後的套接字是被動套接字,用來接收新的客戶端的鏈接請求的,而accept返回的新套接字是標記這個新客戶端的
-
關閉listen後的套接字意味著被動套接字關閉了,會導致新的客戶端不能夠鏈接伺服器,但是之前已經鏈接成功的客戶端正常通信。
-
關閉accept返回的套接字意味著這個客戶端已經服務完畢
-
當客戶端的套接字調用close後,伺服器端會recv解堵塞,並且返回的長度為0,因此伺服器可以通過返回數據的長度來區別客戶端是否已經下線
四、案例:文件下載器
伺服器參考代碼如下:
from socket import *
def get_file(file_name):
try:
with open(file_name, 'rb') as f:
content = f.read()
return content
except:
print("%s文件不存在" % file_name)
def main():
# 創建套接字
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 綁定地址
tcp_server_socket.bind(("192.168.1.1", 8002))
# 將主動套接字變為被動套接字
tcp_server_socket.listen(128)
while True:
# 等待客戶端連接
client_socket, client_addr = tcp_server_socket.accept()
# 接受客戶端發來的數據
recv_data = client_socket.recv(1024)
file_name = recv_data.decode("utf-8")
print("對方請求下載的文件:%s" % file_name)
file_content = get_file(file_name)
# 發送文件的數據給客戶端
# 因為獲取打開文件時是以rb方式打開,所以file_content中的數據已經是二
進位的格式,因此不需要encode編碼
if file_content:
client_socket.send(file_content)
else:
client_socket.send("請求的文件不存在".encode('utf-8'))
# 關閉這個套接字
client_socket.close()
# 關閉伺服器
tcp_server_socket.close()
if __name__ == '__main__':
main()
客戶端 參考代碼如下:
from socket import *
# 創建套接字
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# 目的地址
server_ip = input("伺服器ip:")
server_port = input("伺服器port:")
# 連接伺服器
tcp_client_socket.connect((server_ip, int(server_port)))
# 發送下載的文件名
file_name = input("下載的文件名:")
tcp_client_socket.send(file_name.encode('utf-8'))
# 接受文件
file_content = tcp_client_socket.recv(1024)
# 驗證文件是否存在,存在就創建文件
if file_content.decode('utf-8') == "請求的文件不存在":
print("請求的文件不存在")
else:
with open("new_"+file_name, 'wb') as f:
f.write(file_content)
print("文件下載成功")
# 關閉套接字
tcp_client_socket.close()
五、tcp三次握手、四次揮手
tcp三次握手
tcp四次揮手
六、tcp長連接和短連接
TCP在真正的讀寫操作之前,server與client之間必須建立一個連接,
當讀寫操作完成後,雙方不再需要這個連接時它們可以釋放這個連接,
連接的建立通過三次握手,釋放則需要四次握手,
所以說每個連接的建立都是需要資源消耗和時間消耗的。
TCP通信的整個過程,如下圖:
1. TCP短連接
模擬一種TCP短連接的情況:
-
client 向 server 發起連接請求
-
server 接到請求,雙方建立連接
-
client 向 server 發送消息
-
server 回應 client
-
一次讀寫完成,此時雙方任何一個都可以發起 close 操作
在步驟5中,一般都是 client 先發起 close 操作。當然也不排除有特殊的情況。
從上面的描述看,短連接一般只會在 client/server 間傳遞一次讀寫操作!
2. TCP長連接
再模擬一種長連接的情況:
-
client 向 server 發起連接
-
server 接到請求,雙方建立連接
-
client 向 server 發送消息
-
server 回應 client
-
一次讀寫完成,連接不關閉
-
後續讀寫操作...
-
長時間操作之後client發起關閉請求
3. TCP長/短連接操作過程
3.1 短連接的操作步驟是:
建立連接——數據傳輸——關閉連接...建立連接——數據傳輸——關閉連接
3.2 長連接的操作步驟是:
建立連接——數據傳輸...(保持連接)...數據傳輸——關閉連接
4. TCP長/短連接的優點和缺點
-
長連接可以省去較多的TCP建立和關閉的操作,減少浪費,節約時間。
對於頻繁請求資源的客戶來說,較適用長連接。
-
client與server之間的連接如果一直不關閉的話,會存在一個問題,
隨著客戶端連接越來越多,server早晚有扛不住的時候,這時候server端需要採取一些策略,
如關閉一些長時間沒有讀寫事件發生的連接,這樣可以避免一些惡意連接導致server端服務受損;
如果條件再允許就可以以客戶端機器為顆粒度,限制每個客戶端的最大長連接數,
這樣可以完全避免某個蛋疼的客戶端連累後端服務。
- 短連接對於伺服器來說管理較為簡單,存在的連接都是有用的連接,不需要額外的控制手段。
- 但如果客戶請求頻繁,將在TCP的建立和關閉操作上浪費時間和帶寬。
5. TCP長/短連接的應用場景
-
長連接多用於操作頻繁,點對點的通訊,而且連接數不能太多情況。
每個TCP連接都需要三次握手,這需要時間,如果每個操作都是先連接,
再操作的話那麼處理速度會降低很多,所以每個操作完後都不斷開,
再次處理時直接發送數據包就OK了,不用建立TCP連接。
例如:資料庫的連接用長連接,如果用短連接頻繁的通信會造成socket錯誤,
而且頻繁的socket 創建也是對資源的浪費。
-
而像WEB網站的http服務一般都用短鏈接,因為長連接對於服務端來說會耗費一定的資源,
而像WEB網站這麼頻繁的成千上萬甚至上億客戶端的連接用短連接會更省一些資源,
如果用長連接,而且同時有成千上萬的用戶,如果每個用戶都占用一個連接的話,
那可想而知吧。所以併發量大,但每個用戶無需頻繁操作情況下需用短連好。
七、TCP/IP協議(族)
早期的電腦網路,都是由各廠商自己規定一套協議,IBM、Apple和Microsoft都有各自的網路協議,互不相容
為了把全世界的所有不同類型的電腦都連接起來,就必須規定一套全球通用的協議,為了實現互聯網這個目標,互聯網協議族(Internet Protocol Suite)就是通用協議標準。
因為互聯網協議包含了上百種協議標準,但是最重要的兩個協議是TCP和IP協議,所以,大家把互聯網的協議簡稱TCP/IP協議(族)
常用的網路協議如下圖所示:
說明:
網際層也稱為:網路層
網路介面層也稱為:鏈路層
另外一套標準