套接字基础与UDP通信
套接字基礎與UDP通信
- 套接字和UDP
- Python實現套接字編程
- 了解Ping命令
- 服務器端程序
- 客戶機端程序
- 運行程序步驟
- 測試運行結果
- 問題及解決方法
- 代碼提取
套接字和UDP
?? 套接字是網絡中不同主機上的應用進程之間的雙向通信的端點。每個套接字由一個IP地址和一個端口號組成。套接字采用客戶機-服務器架構。服務器監聽指定的端口等待客戶的請求。服務器收到請求后,接受來自客戶機套接字的連接,完成客戶機與服務器的連接。小于1024的端口已經被占用,因此我們可選用的端口號范圍為(1024,65535)。
?? UDP是一種只提供了無連接通信,且不對傳送的數據包進行可靠性保證的傳輸層協議。UDP無需在客戶機和服務器之間建立連接,客戶機向服務器發送請求報文,服務器接收請求報文,向客戶機發送響應報文,關閉套接字連接,客戶機接受響應報文。
Python實現套接字編程
?? Python中提供了socket模塊用于套接字編程,socket方法可以直接創建一個套接字,需要兩個參數協議(AF_INET:IPV4,AF_INET6:IPV6)和套接字類型(SOCK_STREAM:TCP協議,SOCK_DGRAM:UDP協議)。同時服務器端需要用.bind()方法綁定主機IP和端口號。使用UDP發送數據時只能發送ASCII編碼的數據,并且發送的數據必須是字節類型,所以在發送數據時可以使用.encode()方法改變字節編碼。.sendto()和.recvfrom()方法用來發送和接收數據并且需要設置最大的字節數。
了解Ping命令
?? Ping是一種計算機網絡工具,用來測試數據包能否發送到指定的主機。其原理是向目標主機發送請求報文,并等待接受響應報文,通過發送多個報文,可以計算丟包率和網絡實驗。
?? 可利用Windows的命令行程序(Win+R,輸入cmd即可)進行Ping命令。
?? (1)Ping谷歌官網(不可達,數據包丟失)
??(2)Ping百度官網
??(3)ping本主機
??注:如何查看本主機IP:在命令行程序中輸入 ipconfig /all即可
服務器端程序
# UDP服務器程序:UDPServer.py # 服務器IP:192.168.0.106 # 客戶機IP:192.168.0.103 import random from socket import * serverSocket = socket(AF_INET, SOCK_DGRAM) # 創建服務器套接字 serverSocket.bind(('', 6121)) # 綁定服務器套接字和端口號 print("服務器已啟動......") while True: // 等待客戶機的請求rand = random.randint(0, 10) # 生成隨機數,用于模擬概率丟包/超時message, address = serverSocket.recvfrom(2048) # 接收客戶機的請求報文print("報文 '",message.decode(), "' 接收成功", sep="")if rand < 4: # 以一定的概率模擬超時print()continueserverSocket.sendto(message.decode().upper().encode(), address) # 發送響應報文print("報文 '", message.decode().upper(), "' 發送成功\n", sep="") # 打印響應報文發送成功??服務器端程序代碼解析:生成服務器套接字 serverSocket,綁定服務器主機與指定的端口號(此處端口號選用6121),服務器保持等待,等待客戶機請求。接收到客戶機報文后,以一定概率rand模擬超時丟包,如果rand小于4則讓服務器不發生響應報文;否則服務器回傳響應報文。
客戶機端程序
# UDP客戶機程序:UDPClient.py # 服務器IP:192.168.0.106 # 客戶機IP:192.168.0.103 import time import numpy as np from socket import * # 客戶機端套接字設置 clientSocket = socket(AF_INET, SOCK_DGRAM) # 創建客戶機套接字 clientSocket.settimeout(1) # 設置的最大等待時間 serverName = "192.168.0.106" # 服務器主機 message = ["lxy","hny","python","test","deeplearning","net","face","love","hahaha","lalala"] # 發送10個Ping報文 success = [] # 存放接收成功的Ping報文對應的時延 print("正在 Ping",serverName,"具有 51 字節的數據:") # 發送報文 for i in range(10):clientSocket.sendto(message[i].encode(), (serverName,6121)) # 發送Ping報文start = time.perf_counter() # 計時開始try:modifiedMessage,serverAddress = clientSocket.recvfrom(2048) # 等待接收響應Pong報文end = time.perf_counter() # 計時結束print("來自 ", serverName, " 的回復:報文='", modifiedMessage.decode(),"', 字節=",len(message[i]), ", 時延RTT=", end - start, "s。", sep="")success.append(end-start) # 將成功接收響應報文對應的時延保存except : # 異常拋出,程序繼續運行print("[Error]:請求超時") clientSocket.close() # 關閉客戶機套接字## 打印 Ping 的統計信息 print("\n",serverName,"的 Ping 統計信息:\n 數據包:已發送=10 ,已接受=%d ,丟失=%d (%d%% 丟失)"%(len(success),10-len(success),100*(1-len(success)/10))) if len(success)>0:print("往返行程的估計時間(以秒為單位):\n 最短=%6fs,最長=%6fs,平均=%7fs"%(min(success),max(success),np.mean(success)),sep="")??客戶機端程序代碼解析:生成客戶機套接字,基于服務器主機(使用“127.0.0.1”或者使用IP:192.168.0.103)和端口號向服務器發送10次Ping報文,保持靜默等待服務器回復;若客戶機能夠接收到響應報文則計算時延和輸出報文,若不能接收到Pong報文則輸出“請求超時”;發送10次Ping報文后,統計10次Ping報文的丟包率和時延。
??注:程序中使用time.perf_counter()計時,而不是time.time()是因為前者精度更高。
運行程序步驟
(1)運行服務器程序UDPServer.py,保持服務器在正常工作中,即不能終止程序。
(2)運行客戶機程序UDPClient.py。
測試運行結果
(1)客戶機程序和服務器程序在同一主機上運行(左為服務器控制臺輸出,右為客戶機控制臺輸出)
(2)客戶機程序和服務器程序在不同主機上運行(左為服務器控制臺輸出,右為客戶機控制臺輸出)
問題及解決方法
(1)報錯:Socket.gaierror: [Error 11001] getaddrinfo failed
??主機IP有誤,應該選用主機IP而不是主機名
(2)報錯:Socket.timeout: timed out
??報錯的原因是settimeout()函數遇到錯誤是會直接報錯而終止程序的運行的,所以應該加上try……except將異常拋出而不讓該函數報錯,影響程序的正常運行。
(3)客戶機向服務器發送10個Ping報文中,若第一個報文是被服務器忽略而不回復時,客戶機程序不會運行下去。
??settimeout(1)設置最大等待時間函數的定義位置不準確,一開始是將該定義放在了recvfrom()函數后,正確的做法應該將這個超時異常提前定義。
代碼提取
??相關代碼可在https://github.com/Hny1216/Socket_UDP.git上提取
總結
以上是生活随笔為你收集整理的套接字基础与UDP通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 金蝶K/3 Cloud 实施笔记
- 下一篇: 2021年全球与中国水上巡航行业市场规模