​​​​网络编程学习探索系列之——广播原理剖析

hello !大家好呀! 欢迎大家来到我的网络编程系列之广播原理剖析,在这篇文章中,

你将会学习到如何在网络编程中利用广播来与局域网内加入某个特定广播组的主机!

希望这篇文章能对你有所帮助,大家要是觉得我写的不错的话,那就点点免费的小爱心吧

                    

目录

 一.什么是广播?

   1.1 广播的概念

 1.2 广播通信原理

二 .如何实现广播通信

2.1 广播的IP地址

IPv4

IPv6

特殊用途的广播地址

2.2 实现步骤 

 2.3 网卡接口信息

 三.广播代码实例


 一.什么是广播?

   1.1 广播的概念

广播是一种网络通信技术,允许数据包(如 IP 数据包)被发送到网络上的所有设备。在广播通信中,数据包不是发送给特定的接收者,而是发送给网络中的所有设备。每个设备都会接收到这个数据包,但只有特定地址的设备会响应。广播通常用于局域网(LAN)中,允许设备之间直接通信,而不需要通过路由器。这种通信方式可以提高网络的效率,因为它避免了数据包在网络中的不必要的转发。

 1.2 广播通信原理

广播通信的工作原理如下:

  1. 发送方:发送方将数据包发送到广播地址。在 IP 网络中,广播地址是一个特殊的 IP 地址,通常是 255.255.255.255。

  2. 网络设备:网络中的每个设备都会接收到这个广播数据包。每个设备都会检查数据包的目的地 IP 地址,以确定是否应该响应。

  3. 响应:如果数据包的目的地 IP 地址与设备自己的 IP 地址匹配,或者设备被配置为响应广播数据包,那么该设备将发送一个响应数据包。

  4. 接收方:发送方(或广播请求的发起方)会接收到来自响应设备的响应数据包。

广播通信通常用于以下场景:

  • 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 语言中实现广播编程:

  1. 创建套接字: 使用 socket 函数创建一个 UDP 套接字。你需要指定协议族(如 AF_INET)和协议类型(如 SOCK_DGRAM)。

  2. 设置套接字选项: 你可能需要设置套接字选项,如 SO_BROADCAST,以允许广播通信。

  3. 绑定套接字: 使用 bind 函数将套接字绑定到一个地址和端口。这个地址通常是广播地址,端口是你选择的用于广播通信的端口。

  4. 发送广播消息: 使用 sendto 函数发送广播消息。你需要指定广播地址和端口,以及消息内容。

  5. 接收广播消息: 如果服务器端需要接收广播消息,可以使用 recvfrom 函数来接收来自广播地址的消息。

  6. 关闭套接字: 完成通信后,使用 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接收消息。

服务器代码:

#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){//信号处理函数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(sock+1 , &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;
}

客户端代码:

#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){//信号处理函数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(sock+1 , &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;
}

好啦!到这里这篇文章就结束啦,关于实例代码中我写了很多注释,如果大家还有不懂得,可以评论区或者私信我都可以哦!! 感谢大家的阅读,我还会持续创造网络编程相关内容的,记得点点小爱心和关注哟!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/811059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode算法训练日记 | day24

一、组合问题 1.题目 Leetcode&#xff1a;第 77 题 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4…

福建单航次最大批量汽车“出海”

3月12日这一天&#xff0c;在福州海关的严密监管下&#xff0c;共有4000辆上汽名爵品牌的汽车被高效有序地装载到“安吉智慧”号滚装船上&#xff0c;这批车辆即将启程前往荷兰、埃及、英国等多个海外市场。在这批出口汽车中&#xff0c;新能源车型占据了显著的比例&#xff0c…

OceanMind海睿思助力企业“数据入表”经济利益流入与生命周期管理

通过多年信息系统的建设与应用&#xff0c;企业积累了大量的数据。同时随着时间的推进&#xff0c;数据规模正以加速度快速增长。从国家到企业&#xff0c;都越来越关注所拥有的数据资源及其蕴含的深厚价值。很多企业已经逐渐认知到数据是重要的战略资源&#xff0c;数据资产化…

游标的定义和类型

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 游标的基本概念 游标从字面上理解为游动的光标&#xff0c;可以使用 Excel 表格来想象游标的作用&#xff0c;游标指向每一行&#xff0c;通过游标访问每行数据。 在 Orac…

2024/4/5—力扣—字符串相乘

代码实现&#xff1a; 方法一&#xff1a;常规解法——超出整数表示范围 long long char_to_num(char *str) {long long num 0;for (int i 0; i < strlen(str); i) {num num * 10 (str[i] - 0);}return num; }char* multiply(char *num1, char *num2) {long long a cha…

Git基础操作及其分支管理

目录 一、git的用处&#xff1f; 1.1 git也不是银弹 二、安装git 三、git基础操作 3.1 创建git本地仓库 3.2 配置Git 3.3 认识工作区、暂存区、版本库 3.4 添加文件 3.5 Git文件目录 3.6 版本回退 3.7 撤销修改 3.7.1 对于工作区的代码&#xff0c;还没有进行add操作…

学习51单片机必备:从电子基础到编程技巧全解析

学习51单片机需要掌握一系列的基础知识和技能&#xff0c;以下是一些主要的学习内容&#xff1a; 电子基础知识 了解基本的电子元件和电路原理是学习单片机的基础。这有助于理解单片机如何与外围设备交互以及如何设计电路。 数字逻辑 理解数字逻辑和布尔代数&#xff0c;对于编…

Redis性能管理和集群的三种模式(二)

一、Redis集群模式 1.1 redis的定义 redis 集群 是一个提供高性能、高可用、数据分片、故障转移特性的分布式数据解决方案 1.2 redis的功能 数据分片&#xff1a;redis cluster 实现了数据自动分片&#xff0c;每个节点都会保存一份数据故障转移&#xff1a;若个某个节点发生故…

探索柔性负荷在综合能源系统中的优化调度策略

柔性负荷&#xff0c;指的是那些可以根据系统需求和市场信号调整其使用模式的负荷。它们包括可平移负荷、可转移负荷和可削减负荷。这些负荷的灵活性为IES&#xff08; Integrated Energy System, 综合能源系统&#xff09;提供了额外的调节能力&#xff0c;有助于平衡供需、提…

MyBatis实例更新

MyBatis具体 准备工作 预编译SQL 新增 更新 查询 //查询员工Select("select * from emp where id #{id}")public Emp getById(Integer id);//方案一:给字段起别名&#xff0c;让别名与实体类属性一致Select("select id,username,password,name,gender,image,j…

DataX案例,MongoDB数据导入HDFS与MySQL

【尚硅谷】Alibaba开源数据同步工具DataX技术教程_哔哩哔哩_bilibili 目录 1、MongoDB 1.1、MongoDB介绍 1.2、MongoDB基本概念解析 1.3、MongoDB中的数据存储结构 1.4、MongoDB启动服务 1.5、MongoDB小案例 2、DataX导入导出案例 2.1、读取MongoDB的数据导入到HDFS 2…

Failed to load dll

Unity运行时提示 dll 加载失败 Plugins: Failed to load ‘Assets/Plugins/xxx.dll’ because one or more of its dependencies could not be loaded. 使用 Dependency Walker 查看这个 dll 引用&#xff0c;一推引用丢失 最后确认是 C 组件缺失 打开 Visual Studio Install…

Java基础入门--第十一章--JDBC(Java Database Connection)Java数据库连接

JDBC 11.1 什么是JDBC11.1.1 JDBC概述11.1.2 JDBC驱动程序 11.2 JDBC的常用API11.3 JDBC编程11.3.1 JDBC 编程步骤11.3.2 实现第一个JDBC程序 我的MySQL的root密码: root 11.1 什么是JDBC 11.1.1 JDBC概述 JDBC的全称是Java数据库连接&#xff08;Java Database Connectivit…

光威神策PRO PCIe 5.0 SSD发布,国产固态硬盘进入10G俱乐部

全球半导体供应链的紧张局势和闪存资源的短缺让许多行业都面临着不小的压力 &#xff0c; 连带的也让消费者难以获取物美价廉的闪存产品 。但是&#xff0c;总有一些企业能够逆流而上&#xff0c; 像是 光威科技这家国产存储品牌&#xff0c; 最近就给国内消费者 带来了一个惊喜…

【JAVA基础篇教学】第六篇:Java异常处理

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第五篇&#xff1a; Java异常处理。 异常处理是Java编程中重要的一部分&#xff0c;它允许开发人员在程序运行时检测和处理各种错误情况&#xff0c;以保证程序的稳定性和可靠性。在Java中&#xff0c;异常被表示为对象&am…

【Kafka】Zookeeper集群 + Kafka集群

Zookeeper 概述 Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 Zookeeper 工作机制★★★ Zookeeper从设计模式角度来理解&#xff1a; 1&#xff09;是一个基于观察者模式设计的分布式服务管理框架&#xff1b; 它负责存储和管理大家都关…

AI大模型创新交汇点:当AI遇见艺术

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

代码随想录算法训练营三刷 day48 |动态规划之 198打家劫舍 213打家劫舍II 337打家劫舍III

三刷day48 198.打家劫舍1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组 213.打家劫舍II情况一&#xff1a;考虑不包含首尾元素情况二&#xff1a;考虑包含首元素&#xff0c;不包含尾元素情况三&…

LinkedList部分底层源码分析

JDK版本为1.8.0_271&#xff0c;以插入和删除元素为例&#xff0c;LinkedList部分源码如下&#xff1a; //属性&#xff0c;底层结构为双向链表 transient Node<E> first; //记录第一个结点的位置 transient Node<E> last; //记录最后一个结点的尾元素 transient …

域控软件安全隔离关键技术剖析:MCU域 VS SOC域

安全隔离的需求 功能安全开发中&#xff0c;软件阶段由软件V模型左边的软件安全需求SSR开始。SSR是从技术安全需求TSR中提取出软件的功能安全需求&#xff0c;大多数情况下具有不同的ASIL等级。 图1 功能安全软件开发V模型 随后&#xff0c;软件安全需求会被分配到软件架构中的…