UDP

1. socket 簡介

2. UDP

 

 

1. socket 簡介

網絡編程,是指讓在不一樣的電腦上的軟件可以進行數據傳遞,即進程之間的通訊。編程

本地的進程間通訊(IPC)

例若有:隊列、同步(互斥鎖、條件變量等)等,這些通訊方式都是一臺機器上不一樣進程之間的通訊方式。服務器

網絡中的進程間通訊

首要解決的問題是如何惟一標識一個進程,不然通訊無從談起!網絡

在本地能夠經過進程PID來惟一標識一個進程,可是在網絡中這是行不通的。socket

其實TCP/IP協議族已經幫咱們解決了這個問題,網絡層的「ip地址」能夠惟一標識網絡中的主機,而傳輸層的「協議+端口」能夠惟一標識主機中的應用程序(進程)。tcp

這樣利用ip地址、協議、端口就能夠標識網絡的進程了,網絡中的進程通訊就能夠利用這個標誌與其它進程進行交互。函數

socket

socket(簡稱套接字)是進程間通訊的一種方式,它與其餘進程間通訊的一個主要不一樣是:它能實現不一樣主機間的進程間通訊,咱們網絡上各類各樣的服務大多都是基於 Socket 來完成通訊的。例如咱們天天瀏覽網頁、QQ 聊天、收發 email 等等。spa

建立socket

在 Python 中使用 socket 模塊的函數 socket :調試

socket.socket(AddressFamily, Type)

函數 socket.socket 建立一個 socket,返回該 socket 的描述符,該函數帶有兩個參數:code

  • Address Family:能夠選擇 AF_INET(用於 Internet 進程間通訊) 或者 AF_UNIX(用於同一臺機器進程間通訊),實際工做中經常使用AF_INET。
  • Type:套接字類型,能夠是 SOCK_STREAM(流式套接字,主要用於TCP協議)或者 SOCK_DGRAM(數據報套接字,主要用於UDP協議)。

示例:視頻

1 >>> import socket
2 >>> # 建立了一個TCP Socket
3 >>> tcp_s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
4 >>> tcp_s  
5 <socket.socket fd=548, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>
6 >>> # 建立了一個UDP Socket
7 >>> udp_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
8 >>> udp_s  
9 <socket.socket fd=620, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0>

 

2. UDP

2.1 UDP介紹

UDP(User Data Protocol)——用戶數據報協議,是一個無鏈接的簡單的面向數據報的運輸層協議。

特色:

  • 不具備可靠性的數據報協議。它只是把應用程序傳給IP層的數據報發送出去,可是並不能保證它們能到達目的地,所以可否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。
  • 因爲UDP在傳輸數據報前不用在客戶和服務器之間創建一個鏈接,且沒有超時重發等機制,包數據順序亂掉時也沒有糾正的功能,再加上UDP自己的處理既簡單又高效,故而傳輸速度很快。
  • 將數據封裝爲數據包,每一個數據報都是一個獨立的信息,包括完整的源地址或目的地址,每一個數據包的大小限制在64K中。

應用場景:(注重速度流暢)

UDP是面向消息的協議,通訊時不須要創建鏈接,數據的傳輸天然是不可靠的,UDP通常用於多點通訊和實時的數據業務,好比

  • 音視頻等多媒體通訊(即時通訊,由於它們即便偶爾丟失一兩個數據包,也不會對接收結果產生太大影響)
  • 廣播通訊(廣播、多播)
  • TFTP(簡單文件傳送)
  • SNMP(簡單網絡管理協議)
  • RIP(路由信息協議,如報告股票市場,航空信息)
  • DNS(域名解釋)

UDP操做簡單,並且僅須要較少的監護,所以一般用於局域網高可靠性的分散系統中client/server應用程序。例如視頻會議系統,並不要求音頻視頻數據絕對的正確,只要保證連貫性就能夠了,這種狀況下顯然使用UDP會更合理一些。

UDP網絡通訊過程:

 

2.2 UDP基礎示例

發送、接收數據

建立一個udp客戶端程序的流程較爲簡單,具體步驟以下:

  1. 建立客戶端套接字
  2. 發送/接收數據
  3. 關閉套接字

示例:

 1 import socket
 2 
 3 # 1. 建立套接字
 4 udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 5 
 6 # 2. 準備接收方的地址
 7 sendAddr = ("192.168.3.4", 8080)
 8 
 9 # 3. 從鍵盤獲取要發送的數據
10 sendData = input("請輸入要發送的數據:")
11 
12 # 4. 發送數據到指定的電腦上
13 udpSocket.send(sendData.encode(), sendAddr)
14 # encode():將 str 轉爲 bytes。
15 # decode():將 bytes 轉爲 str。如咱們從網絡或磁盤上讀取了字節流,那麼讀到的數據就是 bytes。
16 
17 # 5. 等待接收方發送過來的數據
18 recvData = udpSocket.recv(1024)  # 1024表示本次接收數據的最大字節數
19 
20 # 6. 顯示對方發送的數據
21 print(recvData)
22 
23 # 7. 關閉套接字
24 udpSocket.close()

執行效果:

會變的端口號:

從新運行屢次腳本,而後在「網絡調試助手」中,看到的現象以下:

  • 每從新運行一次網絡程序,發送方的端口號會變化,不同的緣由在於,這個數字標識這個網絡程序,當從新運行時,若是沒有肯定到底用哪一個,系統默認會隨機分配。
  • 這個網絡程序在運行的過程當中,這個IP+端口號就惟一標識了這個程序,因此若是其餘電腦上的網絡程序若是想要向此程序發送數據,那麼就須要向這個數字(即端口)標識的程序發送便可。

 

2.3 UDP綁定信息

通常狀況下,在一臺電腦上運行的網絡程序會有不少,而各自用的端口號不少狀況下也不知道。爲了避免與其餘的網絡程序佔用同一個端口號,每每在編程中,udp的端口號通常不綁定。

可是若是須要作成一個接收方的程序的話,是須要綁定的。正如若是報警電話天天都在變,想必世界就會亂了。因此通常服務性的程序,每每須要一個固定的端口號,這就是所謂的端口綁定。

示例:

 1 import socket
 2 
 3 # 建立套接字
 4 udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 5 
 6 # 綁定本地的相關信息,若是一個網絡程序不綁定,系統就會隨機分配
 7 binAddr = ("", 7788)  # IP地址和端口號,IP通常不用寫,表示本機的任何一個IP
 8 udpSocket.bind(binAddr)
 9 
10 # 接收方的地址信息
11 sendAddr = ("192.168.234.1", 8080)
12 
13 # 發送數據
14 sendData = udpSocket.sendto("haha".encode(), sendAddr)
15 
16 # 等待接收方發送過來的數據
17 recvData = udpSocket.recvfrom(1024)  # 1024表示本次接收數據的最大字節數
18 
19 # 顯示對方發送的數據
20 print(recvData)
21 
22 # 關閉套接字
23 udpSocket.close()

執行效果:

 

2.4 UDP小應用

應用1:echo服務器,即把接收的數據再發送回去

 1 import socket
 2 import time
 3 
 4 
 5 # 建立套接字
 6 udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 7 
 8 # 綁定本地的相關信息,若是一個網絡程序不綁定,系統就會隨機分配
 9 binAddr = ("", 7788)  # IP地址和端口號,IP通常不用寫,表示本機的任何一個IP
10 udpSocket.bind(binAddr)
11 
12 # 接收方的地址信息
13 sendAddr = ("192.168.234.1", 8080)
14 
15 num = 1
16 
17 def repeat():
18     # 等待對方發送來的數據
19     recvData = udpSocket.recvfrom(1024)  # 1024即本次接收數據的最大字節數
20     # 將接收的數據再次發送回去
21     udpSocket.sendto(recvData[0], sendAddr)
22     # 統計信息
23     print("已經將接收到的第%d個信息返回給對方,數據內容爲:%s" % (num, recvData[0].decode()))    
24 
25 # 若不使用 try..except... 重試機制,而會出現「遠程主機強制關閉鏈接」的報錯
26 while True:
27     try:
28         repeat()
29     except:
30         repeat()
31     
32 # 關閉套接字
33 udpSocket.close()

注意,若出現「ConnectionResetError: [WinError 10054] 遠程主機強迫關閉了一個現有的鏈接」:出現這種緣由表明遠程過於頻繁,因此遠程懷疑是惡意攻擊。

可使用 try...except...重試,在報錯時從新調用該方法使其從新抓取,直至抓取成功。

執行效果:

應用2:聊天室

模擬一個聊天室,顯示全部接收到的數據。

 1 import socket
 2 import time
 3 
 4 
 5 # 建立套接字
 6 udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 7 
 8 # 綁定本地的相關信息,若是一個網絡程序不綁定,系統就會隨機分配
 9 binAddr = ("", 7788)  # IP地址和端口號,IP通常不用寫,表示本機的任何一個IP
10 udpSocket.bind(binAddr)
11 
12 # 接收方的地址信息
13 sendAddr = ("192.168.234.1", 8080)
14 
15 
16 def repeat():
17     # 等待對方發送來的數據
18     recvData = udpSocket.recvfrom(1024)  # 1024即本次接收數據的最大字節數
19     # 打印消息記錄
20     print("【%s】%s:%s"%(time.ctime(), recvData[1][0], recvData[0].decode()))   
21 
22 
23 while True:
24     try:
25         repeat()
26     except:
27         repeat()
28     
29     
30 # 關閉套接字
31 udpSocket.close()

執行效果:

相關文章
相關標籤/搜索