Python學習筆記(二十九):UDP 通信


網絡通信:

本地的進程間通信可以有很多種,比如隊列、同步(互斥鎖)等;

那麼網絡中進程之間如何通信??

首先要解決的問題是,如何準確標識一個網絡中的進程;

我們知道,網絡中的 ip 地址可以準確的標識一個主機,而 "協議+端口" 可以準確的標識一個主機中的應用程序(進程);

這樣,利用 ip地址、協議、端口 就可以標識網絡的進程了,網絡中的進程可以利用這個標誌與其他進程進行通信;

 

socket:

socket,也稱爲套接字,是進程間通信的一種方式,它與其他進程間通信的一個主要不同是:它能實現不同主機直接的進程間通信,即網絡通信;

在 python 中,使用 socket 模塊中的 socket 函數就可以創建一個 socket,語法如下:

 sock = socket.socket(AddressFamily, Type)

上面方法返回 socket 套接字對象,用於進程間通信;

  • 參數 AddressFamily:表示地址協議族,可以選擇 AF_INET,用於 internet 進程間通信;也可以選擇 AF_UNIX,用於同一臺機器進程間通信;一般常用 AF_INET;

  • 參數 Type:表示套接字類型,可以是 SOCK_STREAM,表示流式套接字,主要用於 TCP 通信;也可以是 SOCK_DGRAM,表示數據報套接字,主要用於 UDP 通信;

 

UDP 簡介:

UDP 是用戶數據報協議,是一個無連接的簡單的面向數據報的運輸層協議。UDP 不提供可靠性,它只是把應用程序傳給 IP 層的數據報發送出去,但是並不能保證它們能到達目的地。

由於 UDP 在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,故而傳輸速度很快。

UDP 是一種面向無連接的協議,每個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。

UDP 數據包括目的端口號和源端口號信息,由於通訊不需要連接,所以可以實現廣播發送。

UDP 傳輸數據時有大小限制,每個被傳輸的數據報必須限定在 64KB 之內。

UDP 是一個不可靠的協議,發送方所發送的數據報並不一定以相同的次序到達接收方。

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

 

UDP 通信客戶端:

創建一個 UDP 通信客戶端的步驟:

1、創建客戶端套接字

2、指定服務端 IP 地址和端口

3、發送/接收數據

4、關閉套接字

# 導入 socket 模塊
import socket

# 通過 socket 模塊中的 socket 方法創建一個 socket 對象並返回;
# 參數1 表示地址協議族,AF_INET 表示用於 internet 進程間通信;
# 參數2 表示套接字類型,SOCK_DGRAM 表示數據報套接字,用於 UDP 通信;
# SOCK_STREAM 表示流式套接字,用於 TCP 通信;
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 指定服務器 ip 地址和端口號
sendAddr = ("127.0.0.1", 8888)

# 發送數據到服務器:
# 使用 sendto 方法,參數1 表示要發送的數據,必須是 bytes 類型;
# 參數2 表示要發送到的服務器的 ip 地址和端口號;
udpSocket.sendto("how are you!".encode("UTF-8"), sendAddr)

# 接收服務器返回的數據:1024 表示最大接收字節數;
# 接收到的數據是一個元祖,包含兩個元素,第一個元素
# 是服務端真正發送的數據,以 bytes 類型發送的;
# 第二個元素是服務端的 ip 地址和端口號;
recvData = udpSocket.recvfrom(1024)
print("服務端發送的數據:", recvData[0].decode("UTF-8"))
print("服務端地址:", recvData[1])

# 關閉套接字
udpSocket.close()

 

UDP 通信服務端:

創建一個 UDP 通信服務端的步驟:

1、創建一個服務端套接字

2、指定本地服務端的 ip 地址和端口

3、綁定本地的 ip 地址和端口

4、接收/發送數據

5、關閉套接字

 

# 導入 socket 模塊
import socket

# 創建 socket
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 指定本地服務端 ip 地址和端口(元祖形式)
# 如果不寫 ip 地址,表示本地任意一個 ip 地址
servAddr = ("", 8888)

# 綁定本地 ip 地址和端口(在作爲服務器的時候需要綁定)
udpSocket.bind(servAddr)

# 接收客戶端發送的數據,1024 表示接收的最大字節數;
# 接收到的數據是一個元祖,包含兩個元素,第一個元素
# 是客戶端真正發送的數據,以 bytes 類型發送的;
# 第二個元素是客戶端的 ip 地址和端口號;
recvData = udpSocket.recvfrom(1024)
print("客戶端發送的數據:", recvData[0].decode("UTF-8"))
print("客戶端地址:", recvData[1])

# 發送數據到客戶端:參數1 表示要發送的數據,必須是 bytes 類型;
# 參數2 表示客戶端的地址,客戶端的地址是通過 recvfrom 方法獲取到的;
udpSocket.sendto("I am fine, thank you!".encode("UTF-8"), recvData[1])

# 關閉套接字
udpSocket.close()

一個 udp 網絡程序,可以不綁定 ip 地址和端口,此時操作系統會隨機進行分配一個端口,如果重新運行程序,端口可能會發生改變;

一個 udp 網絡程序,也可以綁定 ip 地址和端口,如果綁定成功,那麼操作系統用這個端口號,來進行區分收到的網絡數據是否是此進程的;

一般情況下,服務器端需要綁定端口,目的是爲了讓其他的客戶端能夠正確發送到此進程;

客戶端一般不需要綁定,而是讓操作系統隨機分配,這樣就不會出現因爲需要綁定的端口被佔用而導致程序無法運行的情況。

 

UDP 廣播:

廣播就是在一個程序中,可以將數據發送到本網絡中的所有電腦上;

# 導入 socket 模塊
import socket

# 創建 socket
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 指定廣播地址:
# 對於 192.168.1 這個網段來說,192.168.1.255 就是廣播地址;
# 如果是 192.168.2 這個網段,就會發送失敗;
# addr = ("192.168.1.255", 8888)

# 廣播地址還可以寫成下面這樣:表示自動識別當前網段的 ip 地址;
# 推薦下面這種寫法;
addr = ("<broadcast>", 8888)

# 設置套接字,允許發送廣播數據
udpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

# 發送廣播數據,將數據發送到本網絡中的所有電腦中
udpSocket.sendto("hello".encode("UTF-8"), addr)

# 關閉套接字
udpSocket.close()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章