受歡迎的邢臺(tái)做網(wǎng)站sem推廣和seo的區(qū)別
hello !大家好呀!
歡迎大家來(lái)到我的網(wǎng)絡(luò)編程系列之廣播原理剖析,在這篇文章中,
你將會(huì)學(xué)習(xí)到如何在網(wǎng)絡(luò)編程中利用廣播來(lái)與局域網(wǎng)內(nèi)加入某個(gè)特定廣播組的主機(jī)!
希望這篇文章能對(duì)你有所幫助
,大家要是覺(jué)得我寫(xiě)的不錯(cuò)的話(huà),那就點(diǎn)點(diǎn)免費(fèi)的小愛(ài)心吧
!
? ? ? ? ? ? ? ? ? ??
目錄
?一.什么是廣播?
? ?1.1 廣播的概念
?1.2?廣播通信原理
二 .如何實(shí)現(xiàn)廣播通信
2.1 廣播的IP地址
IPv4
IPv6
特殊用途的廣播地址
2.2 實(shí)現(xiàn)步驟?
?2.3 網(wǎng)卡接口信息
?三.廣播代碼實(shí)例
?一.什么是廣播?
? ?1.1 廣播的概念
廣播是一種網(wǎng)絡(luò)通信技術(shù),允許數(shù)據(jù)包(如 IP 數(shù)據(jù)包)被發(fā)送到網(wǎng)絡(luò)上的所有設(shè)備。在廣播通信中,數(shù)據(jù)包不是發(fā)送給特定的接收者,而是發(fā)送給網(wǎng)絡(luò)中的所有設(shè)備。每個(gè)設(shè)備都會(huì)接收到這個(gè)數(shù)據(jù)包,但只有特定地址的設(shè)備會(huì)響應(yīng)。廣播通常用于局域網(wǎng)(LAN)中,允許設(shè)備之間直接通信,而不需要通過(guò)路由器。這種通信方式可以提高網(wǎng)絡(luò)的效率,因?yàn)樗苊饬藬?shù)據(jù)包在網(wǎng)絡(luò)中的不必要的轉(zhuǎn)發(fā)。
?1.2?廣播通信原理
廣播通信的工作原理如下:
-
發(fā)送方:發(fā)送方將數(shù)據(jù)包發(fā)送到廣播地址。在 IP 網(wǎng)絡(luò)中,廣播地址是一個(gè)特殊的 IP 地址,通常是 255.255.255.255。
-
網(wǎng)絡(luò)設(shè)備:網(wǎng)絡(luò)中的每個(gè)設(shè)備都會(huì)接收到這個(gè)廣播數(shù)據(jù)包。每個(gè)設(shè)備都會(huì)檢查數(shù)據(jù)包的目的地 IP 地址,以確定是否應(yīng)該響應(yīng)。
-
響應(yīng):如果數(shù)據(jù)包的目的地 IP 地址與設(shè)備自己的 IP 地址匹配,或者設(shè)備被配置為響應(yīng)廣播數(shù)據(jù)包,那么該設(shè)備將發(fā)送一個(gè)響應(yīng)數(shù)據(jù)包。
-
接收方:發(fā)送方(或廣播請(qǐng)求的發(fā)起方)會(huì)接收到來(lái)自響應(yīng)設(shè)備的響應(yīng)數(shù)據(jù)包。
廣播通信通常用于以下場(chǎng)景:
- DHCP 服務(wù)器:在局域網(wǎng)中,DHCP 服務(wù)器使用廣播來(lái)發(fā)現(xiàn)并分配 IP 地址給新加入網(wǎng)絡(luò)的設(shè)備。
- 網(wǎng)絡(luò)管理:網(wǎng)絡(luò)管理員可以使用廣播來(lái)診斷網(wǎng)絡(luò)問(wèn)題或發(fā)送通知給網(wǎng)絡(luò)中的所有設(shè)備。
- 組播:雖然組播(multicast)與廣播類(lèi)似,但它允許數(shù)據(jù)包發(fā)送給一組特定的接收者,而不是所有設(shè)備。組播通常用于多媒體流等應(yīng)用。
在實(shí)際網(wǎng)絡(luò)環(huán)境中,廣播通信可能會(huì)受到一些限制,例如防火墻規(guī)則或網(wǎng)絡(luò)設(shè)備的配置。此外,由于廣播通信可能會(huì)導(dǎo)致網(wǎng)絡(luò)擁塞,一些網(wǎng)絡(luò)設(shè)備可能會(huì)限制或阻止廣播流量。
二 .如何實(shí)現(xiàn)廣播通信
2.1 廣播的IP地址
在 IP 網(wǎng)絡(luò)中,廣播地址用于將數(shù)據(jù)包發(fā)送到網(wǎng)絡(luò)上的所有設(shè)備。廣播地址可以是 IP 地址的一部分,具體取決于網(wǎng)絡(luò)的地址類(lèi)型和配置。以下是不同 IP 地址類(lèi)型中的廣播地址:
IPv4
在 IPv4 網(wǎng)絡(luò)中,廣播地址通常與子網(wǎng)掩碼有關(guān)。廣播地址可以通過(guò)將子網(wǎng)掩碼中的所有主機(jī)位設(shè)置為 1 來(lái)計(jì)算。例如,如果你有一個(gè)子網(wǎng)掩碼?255.255.255.0
,那么對(duì)于地址?192.168.1.10
,其廣播地址將是?192.168.1.255
。
IPv6
在 IPv6 網(wǎng)絡(luò)中,廣播地址的格式是?ff00::/8
。這個(gè)地址范圍是專(zhuān)門(mén)用于廣播和多播的。然而,與 IPv4 不同,IPv6 網(wǎng)絡(luò)中通常不使用廣播地址來(lái)與網(wǎng)絡(luò)中的所有設(shè)備通信。相反,IPv6 使用多播地址,如?ff02::1
,來(lái)代替廣播地址。
特殊用途的廣播地址
除了上述通用廣播地址外,還有一些特殊用途的廣播地址:
224.0.0.0/4
:這是一個(gè)特殊的多播地址范圍,用于多播組播。255.255.255.255
:這是一個(gè)用于直接連接的廣播地址,通常在同一網(wǎng)絡(luò)段內(nèi)使用。
廣播地址的目的是將數(shù)據(jù)包發(fā)送到網(wǎng)絡(luò)中的所有設(shè)備。在實(shí)際應(yīng)用中,廣播地址的用法和實(shí)現(xiàn)可能會(huì)因網(wǎng)絡(luò)配置和協(xié)議的不同而有所差異。在 IPv4 網(wǎng)絡(luò)中,廣播地址通常與子網(wǎng)掩碼有關(guān);而在 IPv6 網(wǎng)絡(luò)中,廣播地址的用法相對(duì)較少,多播地址更為常見(jiàn)。
例如:我在centos系統(tǒng)上查看我的網(wǎng)卡信息:
我的ens33網(wǎng)卡ip地址為192.168.80.132 那么我的該接口的廣播地址為192.168.80.255
2.2 實(shí)現(xiàn)步驟?
當(dāng)我們了解了廣播的ip地址后,我們就可以著手與廣播的編程實(shí)現(xiàn)了,在編程中實(shí)現(xiàn)廣播通信通常涉及使用特定的網(wǎng)絡(luò)編程接口,如 UDP 套接字。以下是一個(gè)基本的步驟,用于在 C 語(yǔ)言中實(shí)現(xiàn)廣播編程:
-
創(chuàng)建套接字:?使用?
socket
?函數(shù)創(chuàng)建一個(gè) UDP 套接字。你需要指定協(xié)議族(如 AF_INET)和協(xié)議類(lèi)型(如 SOCK_DGRAM)。 -
設(shè)置套接字選項(xiàng):?你可能需要設(shè)置套接字選項(xiàng),如?
SO_BROADCAST
,以允許廣播通信。 -
綁定套接字:?使用?
bind
?函數(shù)將套接字綁定到一個(gè)地址和端口。這個(gè)地址通常是廣播地址,端口是你選擇的用于廣播通信的端口。 -
發(fā)送廣播消息:?使用?
sendto
?函數(shù)發(fā)送廣播消息。你需要指定廣播地址和端口,以及消息內(nèi)容。 -
接收廣播消息:?如果服務(wù)器端需要接收廣播消息,可以使用?
recvfrom
?函數(shù)來(lái)接收來(lái)自廣播地址的消息。 -
關(guān)閉套接字:?完成通信后,使用?
close
?函數(shù)關(guān)閉套接字
?這是一般步驟,其中我們還需要更加多的細(xì)節(jié)和基礎(chǔ)知識(shí),大家可以去看我前面博客哦,這里給出相關(guān)鏈接:[C++/Linux] UDP編程-CSDN博客?,?[C++/Linux] socket套接字函數(shù)-CSDN博客
?2.3 網(wǎng)卡接口信息
同時(shí),對(duì)于客戶(hù)端代碼來(lái)說(shuō),我們需要獲取某個(gè)網(wǎng)卡接口的信息,以便我們得到其多播地址,那就要涉及到struct ifreq
? , 這個(gè)結(jié)構(gòu)通常用于獲取和設(shè)置網(wǎng)絡(luò)接口的參數(shù):
struct ifreq {char ifr_name[IFNAMSIZ]; /* Interface name */union {struct sockaddr ifr_addr;struct sockaddr ifr_dstaddr;struct sockaddr ifr_broadaddr;struct sockaddr ifr_netmask;struct sockaddr ifr_hwaddr;};short ifr_flags; /* Flags */int ifr_ifindex; /* Interface index */int ifr_metric; /* Metric */int ifr_mtu; /* MTU */// 可能還有其他字段...
};
這個(gè)結(jié)構(gòu)中的字段包括:
ifr_name
: 網(wǎng)絡(luò)接口的名稱(chēng),例如 “eth0” 或 “wlan0”。ifr_addr
?等字段: 網(wǎng)絡(luò)接口的地址信息,包括 IP 地址、子網(wǎng)掩碼、廣播地址等。ifr_flags
: 接口的標(biāo)志,如?IFF_UP
(接口已啟動(dòng))、IFF_RUNNING
(接口正在運(yùn)行)等。ifr_ifindex
: 網(wǎng)絡(luò)接口的索引。ifr_metric
: 接口的度量值,用于路由選擇。ifr_mtu
: 接口的最大傳輸單元。
要使用?struct ifreq
,你通常會(huì)創(chuàng)建一個(gè)實(shí)例,設(shè)置適當(dāng)?shù)淖侄?#xff0c;然后通過(guò)?ioctl
?調(diào)用來(lái)獲取或設(shè)置網(wǎng)絡(luò)接口的屬性。例如,獲取指定接口的 IP 地址,你可以這樣做:
int sockfd;
struct ifreq ifr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);// 復(fù)制接口名稱(chēng)到ifr_name
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);// 使用SIOCGIFADDR ioctl命令獲取接口地址
if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1) {perror("ioctl");return 1;
}// 現(xiàn)在ifr.ifr_addr包含IP地址
printf("IP Address: %s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));close(sockfd);
這段代碼打開(kāi)了一個(gè)數(shù)據(jù)報(bào)套接字,將接口名稱(chēng)設(shè)置為 “eth0”,然后使用?ioctl
?獲取該接口的 IP 地址,并將其打印出來(lái)。?
?三.廣播代碼實(shí)例
在這個(gè)例子中,服務(wù)器在局域網(wǎng)上偵聽(tīng),當(dāng)有數(shù)據(jù)到來(lái)的時(shí)候,判斷udp數(shù)據(jù)報(bào)中是否含有關(guān)鍵字? ?IP_FOUND,如果有,說(shuō)明此為某客戶(hù)端的廣播通訊消息,服務(wù)器會(huì)回應(yīng)含IP_FOUND_ACK關(guān)鍵字的消息給客戶(hù)端,如果客戶(hù)端收到這條消息,就會(huì)判斷該局域網(wǎng)上目前存在服務(wù)器,同時(shí)可以在消息里說(shuō)明服務(wù)器的ip地址,這樣客戶(hù)端更能了解到當(dāng)前局域網(wǎng)上的服務(wù)器信息,由于是UDP數(shù)據(jù)報(bào),我們使用sendto發(fā)送數(shù)據(jù),recvfrom接收消息。
服務(wù)器代碼:
#include<t_stdio.h>
#include<t_file.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <sys/select.h>
#include<stdlib.h>
#include <arpa/inet.h>
#include<signal.h>
#define DBGPRINT printfvoid sig_process(int signo){//信號(hào)處理函數(shù)printf("catch a exit signal..\n");_exit(0);
}int main(int argc ,char * argv[]){int ret = -1;int sock = -1;int count;socklen_t from_len;struct sockaddr_in local_addr ; //本地地址struct sockaddr_in client_addr ; //客戶(hù)端地址fd_set readfd ; //文件描述符集合,用于接收客戶(hù)端請(qǐng)求char buffer[32];//設(shè)置數(shù)據(jù)數(shù)組,用于數(shù)據(jù)接收發(fā)送struct timeval timeout ;//超時(shí)設(shè)置timeout.tv_sec = 2;timeout.tv_usec = 0;signal(SIGINT,sig_process);//添加sigint信號(hào)到信號(hào)掩碼//創(chuàng)建數(shù)據(jù)報(bào)套接字sock = socket(AF_INET , SOCK_DGRAM , 0);if(sock < 0) E_MSG("socket",-1);//本地地址數(shù)據(jù)清零//memset((void *)local_addr, 0 , sizeof(struct sockaddr_in));//設(shè)置本地地址數(shù)據(jù)local_addr.sin_family = AF_INET;local_addr.sin_addr.s_addr = htonl(INADDR_ANY);//本地地址local_addr.sin_port = htons(8888); //用8888端口進(jìn)行監(jiān)聽(tīng)//本地綁定ret = bind(sock , (struct sockaddr *)&local_addr, sizeof(local_addr));if(ret!=0)E_MSG("bind",-1);//主處理過(guò)程while(1){//先將文件描述符清零FD_ZERO(&readfd);//將套接字文件描述符加入讀集合FD_SET(sock,&readfd);//監(jiān)聽(tīng)是否有數(shù)據(jù)到來(lái)ret = select(sock+1 , &readfd , NULL,NULL,&timeout);printf("ret is : %d/n" , ret);switch (ret){case -1 ://發(fā)生錯(cuò)誤,break;case 0 :// 超時(shí)break;default: //有數(shù)據(jù)到來(lái)if(FD_ISSET(sock , &readfd)){//接收數(shù)據(jù)from_len = sizeof(client_addr); // 初始化from_lencount = recvfrom(sock , buffer , 32 , 0 ,(struct sockaddr *) & client_addr, from_len);DBGPRINT("recv msg is %s\n", buffer);//打印接收的信息if(strstr(buffer , "IP_FOUND")){//查看是否為ip廣播請(qǐng)求數(shù)據(jù)報(bào)//將應(yīng)答數(shù)據(jù)復(fù)制進(jìn)去memcpy(buffer , "IP_FOUND_ACK" , strlen("IP_FOUND_ACK")+1);//發(fā)送應(yīng)答數(shù)據(jù)count = sendto(sock , buffer , strlen(buffer) , 0 ,(struct sockaddr *)&client_addr,from_len);}}}}return 0;
}
客戶(hù)端代碼:
#include<t_stdio.h>
#include<t_file.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <sys/select.h>
#include<stdlib.h>
#include <arpa/inet.h>
#include<signal.h>
#include<net/if.h>
#include <sys/ioctl.h>
#define DBGPRINT printfvoid sig_process(int signo){//信號(hào)處理函數(shù)printf("catch a exit signal..\n");_exit(0);
}int main(int argc ,char * argv[]){int ret = -1 , sock = -1 , so_broadcast = 1, from_len = 0, count = 0;struct ifreq ifr;struct sockaddr_in broadcast_addr ; //本地廣播地址struct sockaddr_in server_addr ; //服務(wù)器地址fd_set readfd ; //設(shè)置接收信息合集,和服務(wù)器代碼一樣char buffer[32];//設(shè)置數(shù)據(jù)數(shù)組,用于數(shù)據(jù)接收發(fā)送struct timeval timeout ;//超時(shí)設(shè)置timeout.tv_sec = 2;timeout.tv_usec = 0;signal(SIGINT,sig_process);//添加sigint信號(hào)到信號(hào)掩碼sock = socket(AF_INET , SOCK_DGRAM , 0); //創(chuàng)建UDP數(shù)據(jù)報(bào)套接字if(sock < 0 ) E_MSG("socket" , -1);//將需要使用的網(wǎng)絡(luò)接口字符串復(fù)制到網(wǎng)卡結(jié)構(gòu)中strcpy(ifr.ifr_name , "ens33");//獲取廣播地址if(ioctl(sock,SIOCGIFBRDADDR, &ifr ) == -1){E_MSG("ioctl",-1);}//將獲得的廣播地址給本地廣播地址結(jié)構(gòu)memcpy(&broadcast_addr , &ifr.ifr_broadaddr , sizeof(struct sockaddr_in));//設(shè)置廣播端口broadcast_addr.sin_port = htons(8888) ; //設(shè)置廣播端口//設(shè)置套接字可以進(jìn)行廣播操作ret = setsockopt(sock , SOL_SOCKET , SO_BROADCAST , &so_broadcast ,sizeof(so_broadcast));//開(kāi)始發(fā)送廣播信息int times = 10 , i = 0 ;for(i = 0 ; i < times ; i++){//廣播發(fā)送服務(wù)器地址請(qǐng)求ret = sendto(sock , "IP_FOUND" , strlen("IP_FOUND") , 0 ,(struct sockaddr * ) &broadcast_addr , sizeof(broadcast_addr));if(ret == -1)continue ; //發(fā)送失敗就繼續(xù)下一次發(fā)送//先將文件描述符清零FD_ZERO(&readfd);//將套接字文件描述符加入讀集合FD_SET(sock,&readfd);//監(jiān)聽(tīng)是否有數(shù)據(jù)到來(lái)ret = select(sock+1 , &readfd , NULL,NULL,&timeout); //這里和服務(wù)器代碼一樣switch (ret){case -1://發(fā)生錯(cuò)誤break;case 0 ://超時(shí)break;default://成功監(jiān)聽(tīng)到服務(wù)器回應(yīng)if(FD_ISSET(sock , &readfd)){count = recvfrom(sock , buffer , 32 , 0 ,(struct sockaddr *)&server_addr , &from_len );DBGPRINT("recv msg is %s\n" , buffer);//判斷是否為廣播回應(yīng)消息if(strstr(buffer , "IP_FOUND_ACK")){printf("found server IP is %s\n", inet_ntoa(server_addr.sin_addr));//打印服務(wù)器ip地址}break;}}}return 0;
}
好啦!到這里這篇文章就結(jié)束啦,關(guān)于實(shí)例代碼中我寫(xiě)了很多注釋,如果大家還有不懂得,可以評(píng)論區(qū)或者私信我都可以哦!! 感謝大家的閱讀,我還會(huì)持續(xù)創(chuàng)造網(wǎng)絡(luò)編程相關(guān)內(nèi)容的,記得點(diǎn)點(diǎn)小愛(ài)心和關(guān)注喲!