第二十七天- 網路通信協議 TCP UDP 緩衝區

来源:https://www.cnblogs.com/xi1419/archive/2018/11/23/10005240.html
-Advertisement-
Play Games

1.網路通信協議 osi七層模型:按照分工不同把互聯網協議從邏輯上劃分了層級 socket層 2.理解socket: Socket是應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對 ...


 

 

1.網路通信協議

  osi七層模型:按照分工不同把互聯網協議從邏輯上劃分了層級

 

 

  socket層

 

2.理解socket:

  Socket是應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對用戶來說,一組簡單的介面就是全部,讓Socket去組織數據,以符合指定的協議。我們可理解成模塊,直接拿來用。

 

套接字socket歷史:

套接字起源於 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix。 因此,有時人們也把套接字稱為“伯克利套接字”或“BSD 套接字”。一開始,套接字被設計用在同 一臺主機上多個應用程式之間的通訊。這也被稱進程間通訊,或 IPC。套接字有兩種(或者稱為有兩個種族),分別是基於文件型的和基於網路型的。 

 

  基於文件類型的套接字家族: 

  套接字家族的名字:AF_UNIX

  unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,可以通過訪問同一個文件系統間接完成通信

 

  基於網路類型的套接字家族:

  套接字家族的名字:AF_INET

  AF_INET6被用於ipv6,還有一些其他的地址家族,不過,基本沒用,所有地址家族中,AF_INET是使用最廣泛的一 個 ,python支持多種地址家族,不過我們主要用網路編程,所以主要還是AF_INET

 

 

3.基於TCP和UDP兩個協議下socket的通訊

  TCP(Transmission Control Protocol)可靠的、面向連接的協議(eg:打電話)、傳輸效率低全雙工通信(發送緩存&接收緩存)、面向位元組流。使用TCP的應用:Web瀏覽器;電子郵件、文件傳輸程式。

  UDP(User Datagram Protocol)不可靠的、無連接的服務,傳輸效率高(發送前時延小),一對一、一對多、多對一、多對多、面向報文,盡最大努力服務,無擁塞控制。使用UDP的應用:功能變數名稱系統 (DNS);視頻流;IP語音(VoIP)。

 

 

tcp協議下的socket:

  伺服器端先初始化Socket,然後與埠綁定(bind),對埠進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接伺服器(connect),如果連接成功,這時客戶端與伺服器端的連接就建立了。客戶端發送數據請求,伺服器端接收請求並處理請求,然後把回應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束

 

註意:tcp是基於鏈接的,必須先啟動服務端,然後再啟動客戶端去鏈接服務端

基本代碼:

server端

 1 import socket
 2 sk = socket.socket()
 3 sk.bind(('127.0.0.1',8898))  #把地址綁定到套接字
 4 sk.listen()          #監聽鏈接
 5 conn,addr = sk.accept() #接受客戶端鏈接
 6 ret = conn.recv(1024)  #接收客戶端信息
 7 print(ret)       #列印客戶端信息
 8 conn.send(b'hi')        #向客戶端發送信息
 9 conn.close()       #關閉客戶端套接字
10 sk.close()        #關閉伺服器套接字(可選)

client端

1 import socket
2 sk = socket.socket()           # 創建客戶套接字
3 sk.connect(('127.0.0.1',8898))    # 嘗試連接伺服器
4 sk.send(b'hello!')
5 ret = sk.recv(1024)         # 對話(發送/接收)
6 print(ret)
7 sk.close()            # 關閉客戶套接字

 

相關bug:

1.socket綁定IP和埠時可能出現下麵的問題:不讓重覆使用埠

 1 #加入一條socket配置,重用ip和埠
 2 import socket
 3 from socket import SOL_SOCKET,SO_REUSEADDR
 4 sk = socket.socket()
 5 sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #在bind前加,允許地址重用
 6 sk.bind(('127.0.0.1',8898))  #把地址綁定到套接字
 7 sk.listen()          #監聽鏈接
 8 conn,addr = sk.accept() #接受客戶端鏈接
 9 ret = conn.recv(1024)   #接收客戶端信息
10 print(ret)              #列印客戶端信息
11 conn.send(b'hi')        #向客戶端發送信息
12 conn.close()       #關閉客戶端套接字
13 sk.close()        #關閉伺服器套接字(可選)
View 解決辦法 Code

若任然報錯,出現 OSError: [WinError 10013] 以一種訪問許可權不允許的方式做了一個訪問套接字的嘗試那麼只能換埠了,因為你的電腦不支持埠重用。

 

2.遠程主機強迫關閉了一個先有連接

這是由於強制斷開造成的,解決很簡單,誰依賴於誰,先關掉依賴者,再關閉被依賴者就好;還有一種是和多個連接造成,tcp協議下最好一對一,一對多可見下麵代碼。

 1 import socket
 2 
 3 server = socket.socket()
 4 ip_port = ('127.0.0.1',8081)
 5 server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)  # 固定寫法,允許地址重用,若還報錯OSerror,系統原因,改埠
 6 
 7 server.bind(ip_port)
 8 server.listen()  # 監聽 可跟參數 n 代表監聽n+1次 如,listen(3),意思是我連接著一個,後面還有3排隊,共4個.
 9 
10 while 1:
11     conn,addr = server.accept()  # 阻塞等待連接
12     while 1:
13         server_msg = input('>>>>> ')
14         server_msg = server_msg.encode('utf-8')
15         conn.send(server_msg)  # 發消息
16         if server_msg == 'byebye':  # 多個客戶端連接時,結束前一個後,跳出當前迴圈到上一個while,重新獲得連接
17             break
18 
19         from_client_msg = conn.recv(1024)  # 接消息
20         from_client_msg = from_client_msg.decode('utf-8')
21         if from_client_msg == 'byebye':
22             break
23         print('來自客戶端的消息:',from_client_msg)
24     conn.close()
View 一對多_服務端 Code
 1 import socket
 2 
 3 client = socket.socket()
 4 server_ip = ('127.0.0.1',8081)
 5 client.connect(server_ip)
 6 
 7 while 1:
 8     from_server_msg = client.recv(1024)
 9     from_server_msg = from_server_msg.decode('utf-8')
10     print('來自伺服器>>>',from_server_msg)
11     if from_server_msg == 'byebye':
12         break
13 
14     client_msg = input('>>>>> ')
15     client_msg = client_msg.encode('utf-8')
16     client.send(client_msg)
17     if client_msg == 'byebye':
18         break
19 
20 client.close()
View 一對多_客戶端 Code
 1 # 再來一份即可
 2 import socket
 3 
 4 client = socket.socket()
 5 server_ip = ('127.0.0.1',8081)
 6 client.connect(server_ip)
 7 
 8 while 1:
 9     from_server_msg = client.recv(1024)
10     from_server_msg = from_server_msg.decode('utf-8')
11     print('來自伺服器>>>',from_server_msg)
12     if from_server_msg == 'byebye':
13         break
14 
15     client_msg = input('>>>>> ')
16     client_msg = client_msg.encode('utf-8')
17     client.send(client_msg)
18     if client_msg == 'byebye':
19         break
20 
21 client.close()
View 一對多_客戶端01 Code

 

總結:用socket進行通信,必須是一收一發對應好。

 

 

udp協議下的socket

  伺服器端先初始化Socket,然後與埠綁定(bind),recvform接收消息,這個消息有兩項,消息內容和對方客戶端的地址,然後回覆消息時也要帶著你收到的這個客戶端的地址,發送回去,最後關閉連接,一次交互結束。

 

 

註意:udp是無鏈接的,啟動服務之後可以直接接受消息,不需要提前建立鏈接,但在發消息時要跟上地址。

基本 代碼:

server端

1 import socket
2 udp_sk = socket.socket(type=socket.SOCK_DGRAM)   #創建一個伺服器的套接字
3 udp_sk.bind(('127.0.0.1',9000))        #綁定伺服器套接字
4 msg,addr = udp_sk.recvfrom(1024)
5 print(msg)
6 udp_sk.sendto(b'hi',addr)                 # 對話(接收與發送)
7 udp_sk.close()                         # 關閉伺服器套接字

client端:

1 import socket
2 ip_port=('127.0.0.1',9000)
3 udp_sk=socket.socket(type=socket.SOCK_DGRAM)
4 udp_sk.sendto(b'hello',ip_port)
5 back_msg,addr=udp_sk.recvfrom(1024)
6 print(back_msg.decode('utf-8'),addr)

 

 

4.練習代碼:

 

#  用戶登錄作業用tcp協議下的socket寫:
# 1. 服務端
# - 等待客戶端來發送數據:用戶名、密碼
# - 本地文件中查看用戶名密碼是否合法。
# - 合法:登錄成功
# - 否則:用戶名或密碼錯誤

# 2. 客戶端
# - 用戶輸入:用戶名、密碼
# - 發送到服務端進行校驗。
 1 import socket
 2 import time
 3 
 4 server = socket.socket()
 5 ip_port = ('127.0.0.1',8083)
 6 server.bind(ip_port)
 7 server.listen()
 8 conn,addr = server.accept()  # 等待conn
 9 
10 dic = {'張三':'123','趙四':'345','王八':'567'}
11 
12 client_msg = conn.recv(1024)
13 client_msg = client_msg.decode('utf-8')  # 還原成字典
14 client_msg = eval(client_msg)
15 print(client_msg)
16 time.sleep(5)
17 
18 for k in dic:
19     if {k:dic[k]} == client_msg:
20         conn.send('登錄成功!'.encode('utf-8'))
21     else:
22         conn.send('用戶名或密碼錯誤!'.encode('utf-8'))
View 服務端 Code
 1 import socket
 2 
 3 client = socket.socket()
 4 server_ip = ('127.0.0.1',8083)
 5 client.connect(server_ip)
 6 
 7 k = input('請輸入賬戶:')
 8 v = input('請輸入密碼:')
 9 # 存入字典,發送給服務端
10 msg = {k:v}
11 client.send(str(msg).encode('utf-8'))
12 
13 from_server_msg = client.recv(1024)
14 print(from_server_msg.decode('utf-8'))
View 客戶端 Code

 

# udp協議下的socket聊天工具(類10086)
# 1. 服務端
# - 接收客戶端發送的信息並作出回覆。
# - 檢查是否有某些指定關鍵字並回覆消息,如果發送過來的消息中還有sb字元串,那麼將sb替換成alexsb,然後和你要輸入的內容組合起來發送給客戶端。
# 2. 多個客戶端
# - 客戶端向服務端發送信息
 1 import socket
 2 
 3 talk_server = socket.socket(type=socket.SOCK_DGRAM)
 4 ip_port = ('127.0.0.1',8086)
 5 talk_server.bind(ip_port)
 6 
 7 while 1:
 8     from_client_msg,addr = talk_server.recvfrom(1024)
 9     from_client_msg = from_client_msg.decode('utf-8')
10     print('來自客戶端>>>',from_client_msg)
11     if from_client_msg == 'byebye':
12         break
13 
14     msg = input('>>> ')
15     if 'sb'in from_client_msg:
16         msg2 = from_client_msg.replace('sb', 'alexsb')
17         talk_server.sendto((msg+msg2).encode('utf-8'),addr)
18     else:
19         talk_server.sendto(msg.encode('utf-8'), addr)
20 
21 talk_server.close()
View 服務端 Code
 1 # udp下複製多個以下代碼即可實現多客戶端 
 2 
 3 import socket
 4 
 5 talk_client = socket.socket(type=socket.SOCK_DGRAM)
 6 server_ip_port = ('127.0.0.1',8086)
 7 
 8 while 1:
 9     msg = input('>>>')
10     if msg == 'byebye':
11         break
12     msg = msg.encode('utf-8')
13     talk_client.sendto(msg,server_ip_port)
14 
15     from_server_msg,addr = talk_client.recvfrom(1024)
16     print('來自服務端>>>',from_server_msg.decode('utf-8'))
17 
18 talk_client.close()
View 客戶端 Code

 

 

5.緩衝區:

# 緩衝區: socket對象 在接收和發送數據時都是先放到緩衝區,再到目標地址的,這樣可避免網路延遲、數據丟包等.

socket緩衝區解釋:

每個 socket 被創建後,都會分配兩個緩衝區,輸入緩衝區和輸出緩衝區。

write()/send() 並不立即向網路傳數據,而是先將數據寫入緩衝區中,再由TCP協議將數據從緩衝區發送到目標機器。一旦將數據寫入到緩衝區,函數就可以成功返回,不管它們有沒有到達目標機器,也不管它們何時被髮送到網路,這些都是TCP協議負責的事情。

TCP協議獨立於 write()/send() 函數,數據有可能剛被寫入緩衝區就發送到網路,也可能在緩衝區中不斷積壓,多次寫入的數據被一次性發送到網路,這取決於當時的網路情況、當前線程是否空閑等諸多因素,不由程式員控制。

read()/recv() 函數也是如此,也從輸入緩衝區中讀取數據,而不是直接從網路中讀取。



 

  


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

-Advertisement-
Play Games
更多相關文章
  • 直接使用 JDBC 的場景,如果代碼中存在拼接 SQL 語句,那麼很有可能會產生註入,如 安全的寫法是使用 參數化查詢 ( parameterized queries ),即 SQL 語句中使用參數綁定( ? 占位符 ) 和 PreparedStatement,如 使用PreparedStateme ...
  • 1.Map 遍歷: 2.map的長度: int size=Map.size(); ...
  • 前言 網際網路聯繫的是世界各地的電腦(通過電纜),萬維網聯繫的是網上的各種各樣資源(通過文本超鏈接),如靜態的HTML文件,動態的軟體程式······。由於萬維網的存在,處於網際網路中的每台電腦可以很方便地進行消息交流、文件資源交流······。基於網際網路的幫助,我們可以在web客戶端(如瀏覽器等) ...
  • FileManager 圖片管理插件是 TinyMCE下 免費且非官方的文件插件,可上傳/管理的類型包括:文件,圖片,視頻。 本教程主要展示大叔在為安裝開發插件過程中進行調整的修改記錄。 ...
  • 昨天是感恩節,上幼兒園的女兒在老師的叮囑下,晚上為我和老婆洗了腳(形式上的^_^),還給我們每人端了一杯水。看著孩子一天天的長大,懂事,感覺很開心。話說咱們程式員這麼辛苦是為了什麼?不就是為了老婆,孩子,熱炕頭,有一個溫暖幸福的家庭,再捎帶著用代碼改變一下世界嗎?想到這裡,頓時覺得學習,創作博客的勁... ...
  • 有人說,你應該關註時事、財經,甚至流行的電影、電視劇,才有可能趁著熱點寫出爆文;有人說,你別再寫“無聊”的技術文了,因為程式員的圈子真的很小,即便是像鴻祥那樣的招牌大牛,文章是那麼的乾貨,瀏覽量有多少?不到萬吧;有人說,你別妄想在寫作上面知識變現了,因為你寫的文章真的很不優秀,我都不愛看! 我想說, ...
  • Django中每一個模型model都對應於資料庫中的一張表,每個模型中的欄位都對應於資料庫表的列。方便的是,django可以自動生成這些create table, alter table, drop table的操作。其次Django為咱們也提供了後臺管理模塊(Django-Admin),主要功能是 ...
  • 原地址:https://www.cnblogs.com/hongten/p/hongten_java_sleep_wait.html ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...