網路編程—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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...