C語言中文網 目錄

UDP多點廣播(多播)原理及實現

通過多點廣播,可以將數據報以廣播方式式發送到多個客戶端。

若要使用多點廣播,則需要將數據報發送到一個組目標地址,當數據報發出后,整個組的所有主機都能接收到該數據報。IP 多點廣播(或多點發送)實現了將單一信息發送給多個接收者的廣播,其思想是設置一組特殊的網絡地址作為多點廣播地址,每一個多點廣播地址都被看作一個組,當客戶端需要發送和接收廣播信息時,加入該組即可。

IP 協議為多點廣播提供了特殊的 IP 地址,這些 IP 地址的范圍是 224.0.0.0~239.255.255.255。多點廣播示意圖如圖 1 所示。

多點廣播示意圖
圖 1 多點廣播示意圖

從圖 1 中可以看出,當 socket 把一個數據報發送到多點廣播 IP 地址時,該數據報將被自動廣播到加入該地址的所有 socket。該 socket 既可以將數據報發送到多點廣播地址,也可以接收其他主機的廣播信息。

在創建了 socket 對象后,還需要將該 socket 加入指定的多點廣播地址中,socket 使用 setsockopt() 方法加入指定組。

如果創建僅用于發送數據報的 socket 對象,則使用默認地址、隨機端口即可。但如果創建接收數據報的 socket 對象,則需要將該 socket 對象綁定到指定端口;否則,發送方無法確定發送數據報的目標端口。

支持多點廣播的 socket 還可設置廣播信息的 TTL(Time-To-Live),該 TTL 參數用于設置數據報最多可以跨過多少個網絡:
  • 當TTL的值為 0 時,指定數據報應停留在本地主機中;
  • 當TTL的值為 1 時,指定將數據報發送到本地局域網中;
  • 當TTL 的值為 32 時,意味著只能將數據報發送到本站點的網絡上;
  • 當TTL 的值為 64 時,意味著數據報應被保留在本地區;
  • 當TTL 的值為 128 時,意味著數據報應被保留在本大洲;
  • 當TTL 的值為 255 時,意味著數據報可被發送到所有地方;

在默認情況下,TTL 的值為1。

從圖 1 中可以看出,使用 socket 進行多點廣播時所有的通信實體都是平等的,它們都將自己的數據報發送到多點廣播IP地址,并使用 socket 接收其他人發迭的廣播數據報。

下面程序使用 socket 實現了一個基于廣播的多人聊天室。程序只需要一個 socket、兩個線程,其中 socket 既用于發送數據,也用于接收數據;主線程負責讀取用戶的鍵盤輸入內容,并向 socket 發送數據,子線程則負責從 socket 中讀取數據。
import time, socket, threading, os

# 定義本機IP地址
SENDERIP = '192.168.1.88'
# 定義本地端口
SENDERPORT = 30000
# 定義本程序的多點廣播IP地址
MYGROUP = '230.0.0.1'
# 通過type屬性指定創建基于UDP協議的socket
s = socket.socket(type=socket.SOCK_DGRAM)
# 將該socket綁定到0.0.0.0的虛擬IP
s.bind(('0.0.0.0', SENDERPORT))     # ①
# 設置廣播消息的TTL(Time-To-Live)
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64)
# 設置允許多點廣播使用相同的端口
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 將socket進入廣播組
status = s.setsockopt(socket.IPPROTO_IP,
    socket.IP_ADD_MEMBERSHIP,
    socket.inet_aton(MYGROUP) + socket.inet_aton(SENDERIP))
# 定義從socket讀取數據的方法
def read_socket(sock):
    while True:
        data = sock.recv(2048)
        print("信息: ", data.decode('utf-8'))
# 以read_socket作為target啟動多線程
threading.Thread(target=read_socket, args=(s, )).start()
# 采用循環不斷讀取鍵盤輸入,并輸出到socket中
while True:
    line = input('')
    if line is None or line == 'exit':
        break
        os._exit(0)
    # 將line輸出到socket中
    s.sendto(line.encode('utf-8'), (MYGROUP, SENDERPORT))
上面主程序中,第 10 行代碼先創建了一個基于 UDP 協議的 socket 對象,由于需要使用該 socket 對象接收數據報,所以將該 socket 綁定到固定端口(由于只需要綁定到固定端口,因此程序中 ① 號代碼使用了 0.0.0.0 這個虛擬 IP 地址)。

第 18 行代碼將該 socket 對象添加到指定的多點廣播 IP 地址。至于程序中使用 socket 發送和接收數據報的代碼,與前面的程序并沒有區別,故此處不再贅述。

精美而實用的網站,提供C語言、C++、STL、Linux、Shell、Java、Go語言等教程,以及socket、GCC、vi、Swing、設計模式、JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo