網路編程—tcp

来源:https://www.cnblogs.com/ForT/archive/2019/04/06/10661424.html
-Advertisement-
Play Games

一、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伺服器

生活中的電話機

如果想讓別人能更夠打通咱們的電話獲取相應服務的話,需要做以下幾件事情:

  1. 買個手機

  2. 插上手機卡

  3. 設計手機為正常接聽狀態(即能夠響鈴)

  4. 靜靜的等著別人撥打

tcp伺服器

如同上面的電話機過程一樣,在程式中,如果想要完成一個tcp伺服器的功能,需要的流程如下:

  1. socket創建一個套接字

  2. bind綁定ip和port

  3. listen使套接字變為可以被動鏈接

  4. accept等待客戶端的鏈接

  5. 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註意點

  1. tcp伺服器一般情況下都需要綁定,否則客戶端找不到這個伺服器

  2. tcp客戶端一般不綁定,因為是主動鏈接伺服器,所以只要確定好伺服器的ip、port等信息就好,本地客戶端可以隨機

  3. tcp伺服器中通過listen可以將socket創建出來的主動套接字變為被動的,這是做tcp伺服器時必須要做的

  4. 當客戶端需要鏈接伺服器時,就需要使用connect進行鏈接,udp是不需要鏈接的而是直接發送,但是tcp必須先鏈接,只有鏈接成功才能通信

  5. 當一個tcp客戶端連接伺服器時,伺服器端會有1個新的套接字,這個套接字用來標記這個客戶端,單獨為這個客戶端服務

  6. listen後的套接字是被動套接字,用來接收新的客戶端的鏈接請求的,而accept返回的新套接字是標記這個新客戶端的

  7. 關閉listen後的套接字意味著被動套接字關閉了,會導致新的客戶端不能夠鏈接伺服器,但是之前已經鏈接成功的客戶端正常通信。

  8. 關閉accept返回的套接字意味著這個客戶端已經服務完畢

  9. 當客戶端的套接字調用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短連接的情況:

  1. client 向 server 發起連接請求

  2. server 接到請求,雙方建立連接

  3. client 向 server 發送消息

  4. server 回應 client

  5. 一次讀寫完成,此時雙方任何一個都可以發起 close 操作

在步驟5中,一般都是 client 先發起 close 操作。當然也不排除有特殊的情況。

從上面的描述看,短連接一般只會在 client/server 間傳遞一次讀寫操作!

 

2. TCP長連接

再模擬一種長連接的情況:

  1. client 向 server 發起連接

  2. server 接到請求,雙方建立連接

  3. client 向 server 發送消息

  4. server 回應 client

  5. 一次讀寫完成,連接不關閉

  6. 後續讀寫操作...

  7. 長時間操作之後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協議(族)

常用的網路協議如下圖所示:

說明:

網際層也稱為:網路層

網路介面層也稱為:鏈路層

 

另外一套標準

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1 截取字元串有的時候我們在頁面中不需要顯示那麼長的字元串,比如新聞標題,這樣用下麵的例子就可以自定義顯示的長度<#if title.content?length lt 8> <a href>${title.content?default("")}</a> <#else> <a href title ...
  • 第四節 數據類型(列表、元祖) 今日內容 列表 元祖 1、列表 1.格式 2.公共方法 1.len 計算長度 2.索引 輸出某一個元素 3.切片 輸出某一段元素 4.修改(字元串/數字/布爾除外) 5.步長 選取列表中第幾個元素 6.for迴圈 註意:for和while的應用場景: 有窮盡優先使用f ...
  • 作業1import random#引入隨機數模塊xing=["小白","小黃","小王","小陳","小綠"]print("學號\t\t\t姓名\t\tJava\tC語言\tPython\t平均成績\t")listj=[]listc=[]listp=[]lista=[]for i in range(... ...
  • 經過一個多月的時間,終於基本完成了第一個項目,電子黑板 此項目主要適用於電子黑板的銷售和展示,功能並不複雜但是細節很多,前面留下的坑很多,之前ue做的爛,後面ue離職,導致ui做的一樣爛,本身邏輯不清晰導致浪費很多時間 項目主要利用的技術其實並不難,但對於我個人而言是之前沒使用過的所以在此總結一番: ...
  • 上篇我們做了一個WriterActor的例子,主要目的是示範WriterActor如何作為集群分片用persistentActor特性及event-sourcing模式實現CQRS的寫功能。既然是集群分片,那麼我們就在這篇講講WriterActor的部署和測試,因為這個裡面還是有些值得註意的地方。下 ...
  • 三、指針和數組 儘管在某些上下文中數組和指針可相互替換,但在編譯器看來二者完全不同,並且在運行時所表達的含義也不同。 當我們說對象或表達式有類型的時候,我們通常想的是定位器值的類型,也叫做左值。當左值有完全non-const類型時,此類型不是數組類型(因為數組本質是記憶體的一部分,是個只讀常量,譯者註 ...
  • MATLAB除了生孩子,其他全都能做系列。 使用MATLAB進行播放《追光者》,純文本內容哦。 載入的y是哪裡來的呢?當然是調用函數生成的咯。 y中的內容就不展示了,全是數據。 鏈接:!!!!! 鏈接:https://pan.baidu.com/s/1NPh4SaAJZ3ZMiN2M98vL6g 提 ...
  • WebSocket項目筆記 1. What is WebSocket? (以下內容來源於百度百科) WebSocket是一種在單個TCP連接上進行全雙工通信的協議 WebSocket使得客戶端和伺服器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。 在WebSocket API中,瀏覽器 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...