手机怎么做网站卖东西,模板网站修改,收企业做网站备案,小区住宅可以注册公司吗hello #xff01;大家好呀#xff01; 欢迎大家来到我的网络编程系列之广播原理剖析#xff0c;在这篇文章中#xff0c; 你将会学习到如何在网络编程中利用广播来与局域网内加入某个特定广播组的主机#xff01; 希望这篇文章能对你有所帮助#xff0c;大家要是觉得我写… hello 大家好呀 欢迎大家来到我的网络编程系列之广播原理剖析在这篇文章中 你将会学习到如何在网络编程中利用广播来与局域网内加入某个特定广播组的主机 希望这篇文章能对你有所帮助大家要是觉得我写的不错的话那就点点免费的小爱心吧 目录 一.什么是广播 1.1 广播的概念 1.2 广播通信原理
二 .如何实现广播通信
2.1 广播的IP地址
IPv4
IPv6
特殊用途的广播地址
2.2 实现步骤 2.3 网卡接口信息 三.广播代码实例 一.什么是广播 1.1 广播的概念
广播是一种网络通信技术允许数据包如 IP 数据包被发送到网络上的所有设备。在广播通信中数据包不是发送给特定的接收者而是发送给网络中的所有设备。每个设备都会接收到这个数据包但只有特定地址的设备会响应。广播通常用于局域网LAN中允许设备之间直接通信而不需要通过路由器。这种通信方式可以提高网络的效率因为它避免了数据包在网络中的不必要的转发。 1.2 广播通信原理
广播通信的工作原理如下 发送方发送方将数据包发送到广播地址。在 IP 网络中广播地址是一个特殊的 IP 地址通常是 255.255.255.255。 网络设备网络中的每个设备都会接收到这个广播数据包。每个设备都会检查数据包的目的地 IP 地址以确定是否应该响应。 响应如果数据包的目的地 IP 地址与设备自己的 IP 地址匹配或者设备被配置为响应广播数据包那么该设备将发送一个响应数据包。 接收方发送方或广播请求的发起方会接收到来自响应设备的响应数据包。
广播通信通常用于以下场景
DHCP 服务器在局域网中DHCP 服务器使用广播来发现并分配 IP 地址给新加入网络的设备。网络管理网络管理员可以使用广播来诊断网络问题或发送通知给网络中的所有设备。组播虽然组播multicast与广播类似但它允许数据包发送给一组特定的接收者而不是所有设备。组播通常用于多媒体流等应用。
在实际网络环境中广播通信可能会受到一些限制例如防火墙规则或网络设备的配置。此外由于广播通信可能会导致网络拥塞一些网络设备可能会限制或阻止广播流量。
二 .如何实现广播通信
2.1 广播的IP地址
在 IP 网络中广播地址用于将数据包发送到网络上的所有设备。广播地址可以是 IP 地址的一部分具体取决于网络的地址类型和配置。以下是不同 IP 地址类型中的广播地址
IPv4
在 IPv4 网络中广播地址通常与子网掩码有关。广播地址可以通过将子网掩码中的所有主机位设置为 1 来计算。例如如果你有一个子网掩码 255.255.255.0那么对于地址 192.168.1.10其广播地址将是 192.168.1.255。
IPv6
在 IPv6 网络中广播地址的格式是 ff00::/8。这个地址范围是专门用于广播和多播的。然而与 IPv4 不同IPv6 网络中通常不使用广播地址来与网络中的所有设备通信。相反IPv6 使用多播地址如 ff02::1来代替广播地址。
特殊用途的广播地址
除了上述通用广播地址外还有一些特殊用途的广播地址
224.0.0.0/4这是一个特殊的多播地址范围用于多播组播。255.255.255.255这是一个用于直接连接的广播地址通常在同一网络段内使用。
广播地址的目的是将数据包发送到网络中的所有设备。在实际应用中广播地址的用法和实现可能会因网络配置和协议的不同而有所差异。在 IPv4 网络中广播地址通常与子网掩码有关而在 IPv6 网络中广播地址的用法相对较少多播地址更为常见。
例如我在centos系统上查看我的网卡信息 我的ens33网卡ip地址为192.168.80.132 那么我的该接口的广播地址为192.168.80.255 2.2 实现步骤
当我们了解了广播的ip地址后我们就可以着手与广播的编程实现了在编程中实现广播通信通常涉及使用特定的网络编程接口如 UDP 套接字。以下是一个基本的步骤用于在 C 语言中实现广播编程 创建套接字 使用 socket 函数创建一个 UDP 套接字。你需要指定协议族如 AF_INET和协议类型如 SOCK_DGRAM。 设置套接字选项 你可能需要设置套接字选项如 SO_BROADCAST以允许广播通信。 绑定套接字 使用 bind 函数将套接字绑定到一个地址和端口。这个地址通常是广播地址端口是你选择的用于广播通信的端口。 发送广播消息 使用 sendto 函数发送广播消息。你需要指定广播地址和端口以及消息内容。 接收广播消息 如果服务器端需要接收广播消息可以使用 recvfrom 函数来接收来自广播地址的消息。 关闭套接字 完成通信后使用 close 函数关闭套接字 这是一般步骤其中我们还需要更加多的细节和基础知识大家可以去看我前面博客哦这里给出相关链接[C/Linux] UDP编程-CSDN博客 [C/Linux] socket套接字函数-CSDN博客 2.3 网卡接口信息
同时对于客户端代码来说我们需要获取某个网卡接口的信息以便我们得到其多播地址那就要涉及到struct ifreq 这个结构通常用于获取和设置网络接口的参数
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 */// 可能还有其他字段...
};这个结构中的字段包括
ifr_name: 网络接口的名称例如 “eth0” 或 “wlan0”。ifr_addr 等字段: 网络接口的地址信息包括 IP 地址、子网掩码、广播地址等。ifr_flags: 接口的标志如 IFF_UP接口已启动、IFF_RUNNING接口正在运行等。ifr_ifindex: 网络接口的索引。ifr_metric: 接口的度量值用于路由选择。ifr_mtu: 接口的最大传输单元。
要使用 struct ifreq你通常会创建一个实例设置适当的字段然后通过 ioctl 调用来获取或设置网络接口的属性。例如获取指定接口的 IP 地址你可以这样做
int sockfd;
struct ifreq ifr;
sockfd socket(AF_INET, SOCK_DGRAM, 0);// 复制接口名称到ifr_name
strncpy(ifr.ifr_name, eth0, IFNAMSIZ);// 使用SIOCGIFADDR ioctl命令获取接口地址
if (ioctl(sockfd, SIOCGIFADDR, ifr) -1) {perror(ioctl);return 1;
}// 现在ifr.ifr_addr包含IP地址
printf(IP Address: %s\n, inet_ntoa(((struct sockaddr_in *)ifr.ifr_addr)-sin_addr));close(sockfd);这段代码打开了一个数据报套接字将接口名称设置为 “eth0”然后使用 ioctl 获取该接口的 IP 地址并将其打印出来。 三.广播代码实例 在这个例子中服务器在局域网上侦听当有数据到来的时候判断udp数据报中是否含有关键字 IP_FOUND如果有说明此为某客户端的广播通讯消息服务器会回应含IP_FOUND_ACK关键字的消息给客户端如果客户端收到这条消息就会判断该局域网上目前存在服务器同时可以在消息里说明服务器的ip地址这样客户端更能了解到当前局域网上的服务器信息由于是UDP数据报我们使用sendto发送数据recvfrom接收消息。 服务器代码
#includet_stdio.h
#includet_file.h
#include sys/types.h
#include sys/socket.h
#include unistd.h
#include sys/time.h
#include string.h
#include sys/select.h
#includestdlib.h
#include arpa/inet.h
#includesignal.h
#define DBGPRINT printfvoid sig_process(int signo){//信号处理函数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 ; //客户端地址fd_set readfd ; //文件描述符集合,用于接收客户端请求char buffer[32];//设置数据数组用于数据接收发送struct timeval timeout ;//超时设置timeout.tv_sec 2;timeout.tv_usec 0;signal(SIGINT,sig_process);//添加sigint信号到信号掩码//创建数据报套接字sock socket(AF_INET , SOCK_DGRAM , 0);if(sock 0) E_MSG(socket,-1);//本地地址数据清零//memset((void *)local_addr, 0 , sizeof(struct sockaddr_in));//设置本地地址数据local_addr.sin_family AF_INET;local_addr.sin_addr.s_addr htonl(INADDR_ANY);//本地地址local_addr.sin_port htons(8888); //用8888端口进行监听//本地绑定ret bind(sock , (struct sockaddr *)local_addr, sizeof(local_addr));if(ret!0)E_MSG(bind,-1);//主处理过程while(1){//先将文件描述符清零FD_ZERO(readfd);//将套接字文件描述符加入读集合FD_SET(sock,readfd);//监听是否有数据到来ret select(sock1 , readfd , NULL,NULL,timeout);printf(ret is : %d/n , ret);switch (ret){case -1 ://发生错误break;case 0 :// 超时break;default: //有数据到来if(FD_ISSET(sock , readfd)){//接收数据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广播请求数据报//将应答数据复制进去memcpy(buffer , IP_FOUND_ACK , strlen(IP_FOUND_ACK)1);//发送应答数据count sendto(sock , buffer , strlen(buffer) , 0 ,(struct sockaddr *)client_addr,from_len);}}}}return 0;
}
客户端代码
#includet_stdio.h
#includet_file.h
#include sys/types.h
#include sys/socket.h
#include unistd.h
#include sys/time.h
#include string.h
#include sys/select.h
#includestdlib.h
#include arpa/inet.h
#includesignal.h
#includenet/if.h
#include sys/ioctl.h
#define DBGPRINT printfvoid sig_process(int signo){//信号处理函数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 ; //服务器地址fd_set readfd ; //设置接收信息合集和服务器代码一样char buffer[32];//设置数据数组用于数据接收发送struct timeval timeout ;//超时设置timeout.tv_sec 2;timeout.tv_usec 0;signal(SIGINT,sig_process);//添加sigint信号到信号掩码sock socket(AF_INET , SOCK_DGRAM , 0); //创建UDP数据报套接字if(sock 0 ) E_MSG(socket , -1);//将需要使用的网络接口字符串复制到网卡结构中strcpy(ifr.ifr_name , ens33);//获取广播地址if(ioctl(sock,SIOCGIFBRDADDR, ifr ) -1){E_MSG(ioctl,-1);}//将获得的广播地址给本地广播地址结构memcpy(broadcast_addr , ifr.ifr_broadaddr , sizeof(struct sockaddr_in));//设置广播端口broadcast_addr.sin_port htons(8888) ; //设置广播端口//设置套接字可以进行广播操作ret setsockopt(sock , SOL_SOCKET , SO_BROADCAST , so_broadcast ,sizeof(so_broadcast));//开始发送广播信息int times 10 , i 0 ;for(i 0 ; i times ; i){//广播发送服务器地址请求ret sendto(sock , IP_FOUND , strlen(IP_FOUND) , 0 ,(struct sockaddr * ) broadcast_addr , sizeof(broadcast_addr));if(ret -1)continue ; //发送失败就继续下一次发送//先将文件描述符清零FD_ZERO(readfd);//将套接字文件描述符加入读集合FD_SET(sock,readfd);//监听是否有数据到来ret select(sock1 , readfd , NULL,NULL,timeout); //这里和服务器代码一样switch (ret){case -1://发生错误break;case 0 ://超时break;default://成功监听到服务器回应if(FD_ISSET(sock , readfd)){count recvfrom(sock , buffer , 32 , 0 ,(struct sockaddr *)server_addr , from_len );DBGPRINT(recv msg is %s\n , buffer);//判断是否为广播回应消息if(strstr(buffer , IP_FOUND_ACK)){printf(found server IP is %s\n, inet_ntoa(server_addr.sin_addr));//打印服务器ip地址}break;}}}return 0;
}
好啦到这里这篇文章就结束啦关于实例代码中我写了很多注释如果大家还有不懂得可以评论区或者私信我都可以哦 感谢大家的阅读我还会持续创造网络编程相关内容的记得点点小爱心和关注哟