文章目錄
- 一、單播
- 二、廣播
- 三、組播
- 四、任播
- 代碼示例:
- 五、各種播的比較
一、單播
- 單播(Unicast)是一種網絡通信方式,它指的是在網絡中從一個源節點到一個單一目標節點對的傳輸模式。單播傳輸時,數據包從發送端直接發送到指定接收端,而不是廣播給網絡中的所有節點或組播給多個指定節點。單播是最常見的網絡通信方式,主要應用于日常的互聯網通信,如訪問網頁、發送電子郵件、文件下載等。
- 單播的特點
舉個例子
- 當用戶訪問一個網頁時,用戶的設備會通過單播請求服務器的網頁內容,服務器再單播傳輸響應給用戶設備。
- 發送電子郵件也是一個單播過程:郵件從發送者的郵件服務器傳輸到接收者的郵件服務器。
二、廣播
- 什么是廣播?
廣播(Broadcast)這種網絡通信方式,用于將數據從一個節點傳輸到同一網絡中的所有其他節點。廣播數據包會被發送到一個特殊的廣播地址,網絡中的所有設備都會接收到這個數據包,不論設備是否需要該信息。這種通信方式一般用于局域網(LAN)中的信息共享。
廣播這個東西,并不是所有的網絡都支持,通常廣播只是在局域網中,IPv6也不只是廣播。在以太網中使用全1的地址,來表示廣播地址。例如255.255.255.255 。在廣播中,發送端并不指定特定的接收方,而是將數據包發送到該網絡中的所有設備。由于廣播會廣泛傳播,在網絡中光標的數據通常是諸如網絡探測和廣告等,這種方式也常被黑客用來進行入侵和攻擊。
-
廣播的特點
-
廣播的類型
在計算機網絡中,廣播有兩種主要類型
- 有限廣播(Limited Broadcast):
使用特殊的IP地址255.255.255.255
僅在發送數據包的子網中傳播,不能跨越路由器
例如:DHCP請求使用有限廣播,因為客戶端不知道服務器的IP地址 - 定向廣播(Directed Broadcast)
使用的是子網廣播地址,例如在192.168.1.0/24子網中的定向廣播地址是192.。168.1.255 。
定向廣播包只會被發送到特定的子網,因此可以跨越一些允許定向廣播的路由器
通常用于特定子網中發送廣播信息,二人不是整個局域網 - 假如有一個網絡192.168.1.0/224,它的廣播地址是192.168.1.255,那么向1192.168.1.255發送的數據包會被該子網中的所有設備接收
如果有設備A向192.168.1.55發送廣播包,那么192.168.1.0/24子網內的所有設備都會接收到該數據包
使用ping255.255.255.255命令(有限廣播),可以測試網絡中是否有設備響應,常用于網絡調試。
-
廣播的應用場景
-
廣播在不同協議中的使用
- IP v4協議:IPv4中支持廣播,有專門的廣播地址
- IPv6協議:IPv6取消了廣播功能,代之以組播(Multicast)和任播(Anycast)通信方式,組播比廣播高效且對資源利用更優化。
- 代碼示例
下面是一個用C++實現UDP廣播的示例代碼,這個程序將創建一個UDP套接字,并向局域網內的廣播地址發送消息。代碼將消息廣播到默認的局域網廣播地址(如255.255.255.255或某個特定的子網廣播地址,比如192.168.1.255)
注:運行廣播代碼時,請確保防火墻允許廣播包的發送,否則可能會被攔截。另外,這段代碼需要在支持BSD套接字的環境中允許,比如Linux或Windows。
//Linux版本
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
using namespace std;#define BROADCAST_PORT 8888 //發送廣播的端口
#define BROADCAST_IP "255.255.255.255" //廣播地址int main() {//創建UDP套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket");return -1;}//啟用廣播選項int BroadcastEnable = 1;//啟用廣播if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &BroadcastEnable, sizeof(BroadcastEnable))){close(sockfd);perror("setsockopt");return -1;}//配置廣播地址struct sockaddr_in broadcastAddr; //配置廣播地址memset(&broadcastAddr, 0, sizeof(broadcastAddr));broadcastAddr.sin_family = AF_INET;broadcastAddr.sin_addr.s_addr = inet_addr(BROADCAST_IP);broadcastAddr.sin_port = htons(BROADCAST_PORT);//廣播的消息const char* message="HEllo,this is a broadcast message!";//發送廣播消息int sendResult=sendto(sockfd, message, strlen(message),0,(struct sockaddr*)&broadcastAddr,sizeof(broadcastAddr));if(sendResult<0){perror("send Faliure!");}else{cout<<"send success!"<<"and sent:"<<message<<endl;}//關閉套接字close(sockfd);return 0;
}
//Windows版本
#include <iostream>
#include <cstring>
#include <winsock2.h> //Windows套接字庫
#include <Ws2tcpip.h> //Windows套接字IPv4地址庫using namespace std;#pragma comment(lib, "Ws2_32.lib") //自動連接ws2_32.lib庫#define BROADCAST_PORT 8888 //發送廣播的端口
#define BROADCAST_IP "255.255.255.255" //廣播地址int main() {//初始化Winsock庫WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {cerr << "WSAStartup failed." <<WSAGetLastError()<< endl;return -1;}//創建UDP套接字SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket");return -1;}//啟用廣播選項int BroadcastEnable = 1;//啟用廣播if(setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(char *)&BroadcastEnable,sizeof(BroadcastEnable))){cerr<<"setsockopt failed."<<WSAGetLastError()<<endl;closesocket(sockfd);WSACleanup();return -1;}//配置廣播地址struct sockaddr_in broadcastAddr; //配置廣播地址memset(&broadcastAddr, 0, sizeof(broadcastAddr));broadcastAddr.sin_family = AF_INET;broadcastAddr.sin_addr.s_addr = inet_addr(BROADCAST_IP);broadcastAddr.sin_port = htons(BROADCAST_PORT);//廣播的消息const char* message="HEllo,this is a broadcast message!";//發送廣播消息int sendResult=sendto(sockfd, message, strlen(message),0,(struct sockaddr*)&broadcastAddr,sizeof(broadcastAddr));if(sendResult<0){perror("send Faliure!");}else{cout<<"send success!"<<"and sent:"<<message<<endl;}//關閉套接字closesocket(sockfd);return 0;
}
三、組播
- 什么是組播多播?
組播和多播實際上是同一個概念,兩者只是翻譯上的差異。組播(或多播)也是一種網絡通信方法,允許數據只發送一次,但可以由多臺主機接收。其主要應用于需要多個接收方實時同步數據的場景,比如在線視頻直播、網絡游戲、股票行情等
組播通常用于局域網,因為許多路由器和網絡設備(特別是家用和小型網絡設備)不支持跨互聯阿的組播路由。此外,組播的管理和傳輸在局域網中更為高效和可控。。不過,大型企業或互聯網服務提供商可能在其內部網絡中使用組播、以實現高效的數據分發。
- 組播的原理
- 具體來說,在一個局域網中的組播過程如下:
1.假設在局域網內有5臺主機:A、B、C、D、E
2.通過分配一個組播地址和端口(比如239.255.0.1:8888)來定義組
3.現在,如果主機A、B和C加入了這個組播組(即訂閱了233.255.0.。1:8888的組播消息),那么D和E不會收到該組播消息,因為它們沒有加入該組.
4.當A發送一條組播消息到239.255.0.1:8888時,B和C會接收這條消息,而D和E不會收到,因為組播只會將數據發送給加入了該組播地址的主機
5.組播的IP和端口是程序自己隨意選擇的(避開常用端口,要大于1024),只要在239.0.0.0到239.。255.。255.255這個范圍內就可以。
- 代碼實現(基于Windows版本)
發送端
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>#pragma comment(lib, "Ws2_32.lib")using namespace std;int main()
{//初始化WinSockWSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){WSACleanup();return 1;}//創建UDP套接字SOCKET sendsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if(sendsock==INVALID_SOCKET){cerr<<"socket error"<<endl;WSACleanup();return -1;}//設置組播地址和端口sockaddr_in multicastAddr;multicastAddr.sin_family = AF_INET;multicastAddr.sin_addr.s_addr = inet_addr("239.255.0.1");multicastAddr.sin_port = htons(8888);//設置套接字為可廣播,以確保數據可以通過廣播發送到組播地址int ttl = 1;setsockopt(sendsock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));//發送組播消息const char* message = "Hello, multicast!";int sendResult = sendto(sendsock, message, strlen(message), 0, (sockaddr*)&multicastAddr, sizeof(multicastAddr));if(sendResult==SOCKET_ERROR){cerr<<"sendto error"<<endl;closesocket(sendsock);WSACleanup();return -1;}cout<<"sendto success and message is:"<<message<<endl;//關閉套接字closesocket(sendsock);WSACleanup();}
接收端
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>#pragma comment(lib, "Ws2_32.lib")using namespace std;int main()
{//初始化WinSockWSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){WSACleanup();return 1;}//創建UDP套接字SOCKET recvsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if(recvsock==INVALID_SOCKET){cerr<<"socket error"<<endl;WSACleanup();return -1;}//綁定組播地址和端口sockaddr_in recvAddr;recvAddr.sin_family = AF_INET;recvAddr.sin_addr.s_addr = INADDR_ANY;recvAddr.sin_port = htons(8888);if(bind(recvsock,(sockaddr*)&recvAddr,sizeof(recvAddr))==SOCKET_ERROR){cerr<<"bind error"<<endl;closesocket(recvsock);WSACleanup();return -1;}//加入組播組ip_mreq multicastRequest;multicastRequest.imr_multiaddr.s_addr = inet_addr("239.255.0.1");//組播地址multicastRequest.imr_interface.s_addr = INADDR_ANY; //本地任意接口if(setsockopt(recvsock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&multicastRequest,sizeof(multicastRequest))){cerr<<"setsockopt error"<<endl;closesocket(recvsock);WSACleanup();return -1;}//接收組播消息char recvBuf[1024];sockaddr_in senderAddr;int senderAddrLen = sizeof(senderAddr);int recvlen= recvfrom(recvsock,recvBuf,sizeof(recvBuf),0,(sockaddr*)&senderAddr,&senderAddrLen);if(recvlen>0){recvBuf[recvlen] = '\0';cout<<"receive message:"<<recvBuf<<endl;}else{cerr<<"recvfrom error"<<endl;}//退出組播組setsockopt(recvsock,IPPROTO_IP,IP_DROP_MEMBERSHIP,(char *)&multicastRequest,sizeof(multicastRequest));//關閉套接字closesocket(recvsock);WSACleanup();return 0;;
}
- 注意事項
1.組播地址選擇,在局域網中,239.0.0.0到239.255.255.255是專用組播地址,通常用于本地組播
2.TTL設置:通過設置TTL(Time-To_Live)為1,可確保組播消息不會被路由器轉發到其他網段
int ttl = 1;
setsockopt(sendsock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));
IPPORTTO_IP:這個參數指定了將要設置對的選項所需的協議級別,IPPORTTO_IP表示這是IPv4協議級別的選項。對于IPv6,相應的常量是IPPORTTO_IPV6 。
IP_MULTICAST_TTL:這是要設置的選項名,IP_MULTICAST_TTL用于指定多播數據包的生存時間(TTL),TTL定義了數據包在網絡中可以經過的最大路由器數(或跳數)。每當數據包經過一個路由器時,其TTL值減1.當TTL值減到0時,數據包被丟棄。
if(setsockopt(recvsock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&multicastRequest,sizeof(multicastRequest))){cerr<<"setsockopt error"<<endl;closesocket(recvsock);WSACleanup();return -1;}
- sock:套接字描述符
- IPPORTTO_IP:指定選項所在的協議層。
- IP_ADD_MEMBERSHIP:這是要設置選項的名稱。它告訴系統,我們想要將一個套接字加入到一個多播組中
- &multicast_request:指向一個ip_mreq結構的指針,該結構包含了多播組的地址以及本地接口的地址(或者是一個特殊的值來表示所有接口)。這個結構定義了套接字將要加入的多播組。
- ip_mreq結構通常定義如下(在<netinet/in.h>或類似頭文件中):
struct ip_mreq{struct in_addr imr_umltiaddr;//多播組的IP地址struct in_addrr imr_interface;//本地接口的IP地址,或INADDR_ANY表示所有接口
}
- sizeof(multicast_request):指定了multicast_request結構的大小,以字節為單位。
- 代碼實現(基于Linux)
//服務端
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
using namespace std;#define PORT 8080
#define MAX_SIZE 1024int main()
{//創建UDP套接字int sendsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if(sendsock<0){cerr<<"socket error"<<endl;return -1;}//設置組播地址和端口sockaddr_in multicastAddr;multicastAddr.sin_family = AF_INET;multicastAddr.sin_addr.s_addr = inet_addr("239.255.0.1");multicastAddr.sin_port = htons(8888);//設置套接字為可廣播,以確保數據可以通過廣播發送到組播地址int ttl = 1;setsockopt(sendsock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));//發送組播消息const char* message = "Hello, multicast!";int sendResult = sendto(sendsock, message, strlen(message), 0, (sockaddr*)&multicastAddr, sizeof(multicastAddr));if(sendResult<0){cerr<<"sendto error"<<endl;close(sendsock);return -1;}cout<<"sendto success and message is:"<<message<<endl;//關閉套接字close(sendsock);return 0;
}
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
using namespace std;#define PORT 8080
#define MAX_SIZE 1024int main()
{//創建UDP套接字int recvsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if(recvsock<0){cerr<<"socket error"<<endl;return -1;}//綁定組播地址和端口sockaddr_in recvAddr;recvAddr.sin_family = AF_INET;recvAddr.sin_addr.s_addr = INADDR_ANY;recvAddr.sin_port = htons(8888);if(bind(recvsock,(sockaddr*)&recvAddr,sizeof(recvAddr))<0){cerr<<"bind error"<<endl;close(recvsock);return -1;}//加入組播組ip_mreq multicastRequest;multicastRequest.imr_multiaddr.s_addr = inet_addr("239.255.0.1");//組播地址multicastRequest.imr_interface.s_addr = INADDR_ANY; //本地任意接口//接收組播消息char recvBuf[1024];sockaddr_in senderAddr;socklen_t senderAddrLen = sizeof(senderAddr);int recvlen= recvfrom(recvsock,recvBuf,MAX_SIZE,0,(sockaddr*)&senderAddr,&senderAddrLen);if(recvlen>0){recvBuf[recvlen] = '\0';cout<<"receive message:"<<recvBuf<<endl;}else{cerr<<"recvfrom error"<<endl;}//退出組播組setsockopt(recvsock,IPPROTO_IP,IP_DROP_MEMBERSHIP,(char *)&multicastRequest,sizeof(multicastRequest));//關閉套接字close(recvsock);
}
四、任播
- 什么是任播?
任播(Anycast)是指多個服務器或節點共享一個IP地址,通過網絡協議中的路由機制,用戶的請求自動選擇距離最近或最優的服務器進行響應。與傳統的單播(Unicast)和組播(Multicast)不同,任播的核心在于“發送到最近的一個”
任播與組播的區別:在組播中,消息會被發送到一組所有訂閱該IP地址的節點。但在任播中,消息只會到達同一IP地址下的一個最優節點。
任播可以使用任何可路由的IP地址,通常是常規的單播地址(A類、B類或C類IP地址),而不是D類地址。
任播實現的關鍵在于多個主機共享同一單播IP地址,通過路由協議(例如BGP或OSPF)來決定最近或最佳路徑,而不是通過適用特殊的IP地址類被來實現。
-
任播的特點
-
任播的原理
- 任播最優路由決策的過程
任播的最優路由通常由BGP(邊界網關協議)或OSPF(開放式最短路徑優先協議)等網絡路由協議來實現。以下是最優路由的決策過程
-
地理距離和路徑開銷:在同一任播IP地址的情況下,路由器根據用戶的地理位置選擇最短路徑或最低延遲的路徑,以減少數據傳輸時間
-
網絡延遲:當路徑開銷類似時,路由器會優先選擇網絡延遲較低的路徑。網絡延遲可以通過探測或協議交換獲得。
-
路徑穩定性:路由協議會優先選擇路徑穩定性較高的節點,路徑的不穩定性可能會導致路由頻繁更改,從而增加網絡開銷。
-
路由協議的計算與更新:在BGP等動態路由協議中,節點定期交換路由信息,一旦有節點發生變化(如故障、延遲增加),路由表會根據新的路由哦條件進行更新
-
負載平衡機制:如果多個節點的延遲相似,路由器會分配請求給不同節點,以實現負載平衡。這種策略也用于避免某個節點出現瓶頸。
舉個例子:互聯網中的任播-----Google DNS服務
假設你在中國訪問Google的公共DNS服務器(如IP地址8.8.8.8).Google在全球多個地點(美國、歐洲、亞洲等)部署了多個共享這個IP地址的DNS服務器,這些服務器都配置為任播節點。
- 當你請求訪問8.8.8.8時,路由器會根據你的地理位置和當前的網絡狀況,選擇距離最近或響應最快的服務器節點來處理請求。例如,你的請求會被引導到位于亞洲的一個GoogleDNS服務器,而不是到美國或歐洲的服務器。
- 這樣做的好處是降低了請求延遲,用戶可以更快的速度獲得DNS解析結果,同時,入股亞洲的服務器出現故障,請求會自動轉向其他位置的服務器,確保服務的高可用性。
也就是說:在互聯網中的任播應用,通過全局BGP協議實現,將全球用戶的請求引導至最近的服務器節點。
- 再舉個例子就是
- 主句A在北京,而主機B在石家莊、C和D在上海、E在硅谷。所有節點BCDE都監聽同一個任播地址239.255.255.250和端口8080.
- 當A發送UDP消息到任播地址239.255.255.250:8080時,路由協議會選擇一個最優路徑,將消息轉發給其中距離最近的一個節點,而不是多個節點。
代碼示例:
- 場景設定
假設網絡已經配置支持任播
發送方主機A位于北京,向任播地址239.255.255.250發送消息,端口為8080
接收方主機(B、C、D、E)都監聽239.255.255.250:8080上。
我們可以使用UDP套接字實現該功能,并且需要網絡配置支持任播路徑選擇,比確保消息能正確到達距離最近的節點。
- 發送方代碼(主機A)–sender.cpp
發送方會向任播IP地址239.255.255.250的端口8080發送UDP消息。
#include <iostream>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstring>
using namespace std;#define ANYCAST_IP "239.255.255.250" //任播IP地址
#define PORT 8080int main() {int sockdf;struct sockaddr_in servaddr;//創建UDP套接字sockdf = socket(AF_INET, SOCK_DGRAM, 0);if (sockdf < 0) {perror("socket create Failure!");return -1;}//設置目標地址memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port=htons(PORT);if(inet_pton(AF_INET, ANYCAST_IP, &servaddr.sin_addr)<=0)//任播地址{perror("inet_pton Failure!");clsoe(sockdf);return -1;}//準備消息內容const char* message="Hello from A(BeiJing)";int msg_len=strlen(message);//發送消息if(sendto(sockfd,message,msg_len,0,((struct sockaddr*)&servaddr),sizeof(servaddr))<0){perror("sendto Failure!");close(sockdf);return -1;}cout<<"Message send to"<<ANYCAST_IP<<":"<<PORT<<endl;//關閉套接字close(sockdf);return 0;
}
- 接收方代碼(主機B/C/D/E)–receiver.cpp
接收方監聽在任播IP地址239.255.255.250和端口8080上,等待來自發送方的UDP消息
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
using namespace std;#define ANYCAST_IP "239.255.255.250" //任播IP地址
#define PORT 8080int main()
{int sockfd;struct sockaddr_in servaddr,clientaddr;//創建UDP套接字sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){cout << "create socket error" << endl;return -1;}//設置地址復用選項,允許多個節點綁定到相同的端口int opt=1;if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))){cout << "set socket option error" << endl;close(sockfd);return -1;}//設置服務器地址memeset(&servaddr,0,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr(ANYCAST_IP);//綁定套接字來任播地址if(bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0){cout << "bind socket error" << endl;close(sockfd);return -1;}//接收數據char buf[1024];socklen_t len = sizeof(clientaddr);cout<<"Receiver listening on "<<ANYCAST_IP<<":"<<PORT<<endl;while(true){int n = recvfrom(sockfd,buf,sizeof(buf)-1,0,(struct sockaddr *)&clientaddr,&len);if(n<0){perror("recvfrom");break;}buf[n] = '\0';cout<<"Received message :"<<buf<<"from "<<inet_ntoa(clientaddr.sin_addr)<<":"<<ntohs(clientaddr.sin_port)<<endl;}//關閉套接字close(sockfd);return 0;
}
- 代碼說明和重要的函數參數
-
發送方:通過UDP套接字向任播地址239.255.255.250:8080發送消息
-
接收方:通過UDP套接字綁定到相同的任播地址和端口號239.255.255.250:8080,監聽并接收消息。
-
a. 在多個接收方節點(如B、C、D、E)上運行receiver.cpp,并確保網絡配置支持任播
-
b. 在發送方節點A上運行sender.cpp發送消息
-
- 難點代碼
//設置地址復用選項,允許多個節點綁定到相同的端口int opt=1;if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))){cout << "set socket option error" << endl;close(sockfd);return -1;}
(1)sockfd:這是套接字文件描述符,socket()函數返回的值。setsockopt將對這個套接字應用配置選項。
(2)SOL_SOCKET:這是套接字層的選項類型,用于指定選項在套接字級別(例如,SO_REUSEADDR、SO_KEEPALIVE等)。當你想要設置通用的套接字選項(而不是協議特定的選項)時,會將此參數設置為SOL_SOCKET。
(3)SO_REUSEADDR:這是具體的選項標志,表示地址重用。它允許一個本地端口可以被多個套接字綁定,特別是在以下場景中使用:
···
····服務器快速重啟:如果服務器進程使用某個端口并意外終止,那么在短時間內重新啟動該進程時,端口可能還被操作系統標記為“正在使用”,SO_REUSEADDR可以使端口立即可用。
···多播和任播:多個進程可用監聽同一個端口,這對于多播和任播應用非常重要,因為多個服務器實例可能同時監聽同一端口來接收數據。
···端口共享:允許多個套接字同時綁定到同一IP地址和端口,但其中只有一個會接收傳入數據。
···&opt:這是指向opt變量的指針,表示SO_REUSEADDR的值。我們將其設置為1(即opt=1),表示啟用端口重用。若將其設置為0,則表示禁用端口重用。
···sizeof(opt):指定opt的大小,用于告訴setsockopt函數opt變量的長度。
- 預期結果
在正確配置任播的情況下,只有一個接收方節點(例如距離A最近的B節點)會接收到消息,并在控制臺上打印發送方A的消息內容。這是因為任播路由的設計會自動將消息引導到最優路徑的單一節點。
五、各種播的比較
特性 | 單播(Unicast) | 廣播(Broadcast) | 任播(Anycast) | 組播(Multicast) |
---|---|---|---|---|
地址類型 | A、B、C類IP地址 | D類地址(以255.255.255.255結尾) | A、B、C類IP地址 | D類地址(224.0.0.0-239.255.255.255) |
數據傳輸范圍 | 一個發送者到一個接收者 | 一個發送者到同一網絡內的所有接收者 | 一個發送者到多個節點之一,選擇最近的一個節點 | 一個發送者到指定組內的多個接收者 |
數據傳輸效率 | 效率低,需要多個單獨的傳輸 | 效率低,所有設備都接收,無論是否需要 | 效率較高,只發送到最優接收者 | 效率較高,只發送到訂閱的接收者 |
應用場景 | 點對點通信,例如CS模型 | 局域網中的廣播(如ARP請求) | CDN、DNS等分布式服務,將流量引導到最近節點 | 視頻會議、IPTV、在線直播等 |
IP地址范圍 | 常規單播IP地址(如A類、B類、C類) | 子網廣播(如192.168.1.255),或全網廣播 | 常規單播IP地址(如A類、B類、C類) | D類地址范圍(224.0.0.0-239.255.255.255) |
路由實現 | 常規路由、根據目標單個IP地址 | 不路由,一般局限于局域網內 | 通過路由協議選擇最近或最優的路徑 | 依靠多播路由協議(如PIM) |
典型協議 | TCP、UDP | UDP | BGP(用于選擇最近節點) | IGMP、PIM |
適用范圍 | 適用于需要專用通信的場景 | 局限于局域網 | 廣域網和局域網均適用,要求網絡支持任播配置 | 局域網和廣域網均適用 |
優勢 | 通信明確、安全性高 | 易于實現,無需復雜配置 | 實現負載均衡、提高服務性能 | 節省帶寬、優化數據傳輸效率 |
缺點 | 不適用于大規模接收者的通信 | 消耗帶寬、增加不必要的網絡流量 | 依賴路由協議支持,配置復雜 | 需要額外的組播路由配置 |