TCP/IP网络编程——多播与广播
完整版文章请参考:
TCP/IP网络编程完整版文章
文章目录
- 第 14 章 多播与广播
- 14.1 多播
- 14.1.1 多播的数据传输方式以及流量方面的优点
- 14.1.2 路由(Routing)和 TTL(Time to Live,生存时间),以及加入组的办法
- 14.1.3 实现多播 Sender 和 Receiver
- 14.2 广播
- 14.2.1 广播的理解和实现方法
- 14.2.2 实现广播数据的 Sender 和 Receiver
第 14 章 多播与广播
14.1 多播
多播(Multicast)方式的数据传输是基于 UDP 完成的。因此 ,与 UDP 服务器端/客户端的实现方式非常接近。区别在于,UDP 数据传输以单一目标进行,而多播数据同时传递到加入(注册)特定组的大量主机。换言之,采用多播方式时,可以同时向多个主机传递数据。
14.1.1 多播的数据传输方式以及流量方面的优点
多播的数据传输特点可整理如下:
- 多播服务器端针对特定多播组,只发送 1 次数据。
- 即使只发送 1 次数据,但该组内的所有客户端都会接收数据
- 多播组数可以在 IP 地址范围内任意增加
多播组是 D 类IP地址(224.0.0.0~239.255.255.255),「加入多播组」可以理解为通过程序完成如下声明:
在 D 类IP地址中,我希望接收发往目标 239.234.218.234 的多播数据
多播是基于 UDP 完成的,也就是说,多播数据包的格式与 UDP 数据包相同。只是与一般的 UDP 数据包不同。向网络传递 1 个多播数据包时,路由器将复制该数据包并传递到多个主机。像这样,多播需要借助路由器完成。如图所示:
若通过 TCP 或 UDP 向 1000 个主机发送文件,则共需要传递 1000 次。但是此时如果用多播网络传输文件,则只需要发送一次。这时由 1000 台主机构成的网络中的路由器负责复制文件并传递到主机。就因为这种特性,多播主要用于「多媒体数据实时传输」。
另外,理论上可以完成多播通信,但是不少路由器并不支持多播,或即便支持也因网络拥堵问题故意阻断多播。因此,为了在不支持多播的路由器中完成多播通信,也会使用隧道(Tunneling)技术。
14.1.2 路由(Routing)和 TTL(Time to Live,生存时间),以及加入组的办法
为了传递多播数据包,必须设置 TTL 。TTL 是 Time to Live 的简写,是决定「数据包传递距离」的主要因素。TTL 用整数表示,并且每经过一个路由器就减一。TTL 变为 0 时,该数据包就无法再被传递,只能销毁。因此,TTL 的值设置过大将影响网络流量。当然,设置过小,也无法传递到目标。
接下来是 TTL 的设置方法。TTL 是可以通过第九章的套接字可选项完成的。与设置 TTL 相关的协议层为 IPPROTO_IP ,选项名为 IP_MULTICAST_TTL。因此,可以用如下代码把 TTL 设置为 64
int send_sock;
int time_live = 64;
...
send_sock=socket(PF_INET,SOCK_DGRAM,0);
setsockopt(send_sock,IPPROTO_IP,IP_MULTICAST_TTL,(void*)&time_live,sizeof(time_live);
...
加入多播组也通过设置套接字可选项来完成。加入多播组相关的协议层为 IPPROTO_IP,选项名为 IP_ADD_MEMBERSHIP 。可通过如下代码加入多播组:
int recv_sock;
struct ip_mreq join_adr;
...
recv_sock=socket(PF_INET,SOCK_DGRAM,0);
...
join_adr.imr_multiaddr.s_addr="多播组地址信息";
join_adr.imr_interface.s_addr="加入多播组的主机地址信息";
setsockopt(recv_sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(void*)&join_adr,sizeof(join_adr);
...
下面是 ip_mreq 结构体的定义:
struct ip_mreq
{struct in_addr imr_multiaddr; //写入加入组的IP地址struct in_addr imr_interface; //加入该组的套接字所属主机的IP地址
};
14.1.3 实现多播 Sender 和 Receiver
多播中用「发送者」(以下称为 Sender) 和「接收者」(以下称为 Receiver)替代服务器端和客户端。顾名思义,此处的 Sender 是多播数据的发送主体,Receiver 是需要多播组加入过程的数据接收主体。下面是示例,示例的运行场景如下:
- Sender : 向 AAA 组广播(Broadcasting)文件中保存的新闻信息
- Receiver : 接收传递到 AAA 组的新闻信息。
news_sender.c 程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define TTL 64
#define BUF_SIZE 30
void error_handling(char *message);int main(int argc, char *argv[])
{int send_sock;struct sockaddr_in mul_adr;int time_live = TTL;FILE *fp;char buf[BUF_SIZE];if (argc != 3){printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);exit(1);}send_sock = socket(PF_INET, SOCK_DGRAM, 0); //创建 UDP 套接字memset(&mul_adr, 0, sizeof(mul_adr));mul_adr.sin_family = AF_INET;mul_adr.sin_addr.s_addr = inet_addr(argv[1]); //必须将IP地址设置为多播地址mul_adr.sin_port = htons(atoi(argv[2]));//指定套接字中 TTL 的信息setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&time_live, sizeof(time_live));if ((fp = fopen("news.txt", "r")) == NULL)error_handling("fopen() error");while (!feof(fp)) //如果文件没结束就返回0{fgets(buf, BUF_SIZE, fp);sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&mul_adr, sizeof(mul_adr));sleep(2);}fclose(fp);close(send_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}
news_receiver.c 程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30
void error_handling(char *message);int main(int argc, char *argv[])
{int recv_sock;int str_len;char buf[BUF_SIZE];struct sockaddr_in adr;struct ip_mreq join_adr;if (argc != 3){printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);exit(1);}recv_sock = socket(PF_INET, SOCK_DGRAM, 0);memset(&adr, 0, sizeof(adr));adr.sin_family = AF_INET;adr.sin_addr.s_addr = htonl(INADDR_ANY);adr.sin_port = htons(atoi(argv[2]));if (bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr)) == -1)error_handling("bind() error");//初始化结构体join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]); //多播组地址join_adr.imr_interface.s_addr = htonl(INADDR_ANY); //待加入的IP地址//利用套接字选项 IP_ADD_MEMBERSHIP 加入多播组,完成了接受指定的多播组数据的所有准备setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr));while (1){//通过 recvfrom 函数接受多播数据。如果不需要知道传输数据的主机地址信息,可以向recvfrom函数的第5 6参数分贝传入 NULL 0str_len = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, NULL, 0);if (str_len < 0)break;buf[str_len] = 0;fputs(buf, stdout);}close(recv_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}
通过结果可以看出,使用 sender 多播信息,通过 receiver 接收广播,如果延迟运行 receiver 将无法接受之前发送的信息。
14.2 广播
广播(Broadcast)在「一次性向多个主机发送数据」这一点上与多播类似,但传输数据的范围有区别。多播即使在跨越不同网络的情况下,只要加入多播组就能接受数据。相反,广播只能向同一网络中的主机传输数据。
14.2.1 广播的理解和实现方法
广播是向同一网络中的所有主机传输数据的方法。与多播相同,广播也是通过 UDP 来完成的。根据传输数据时使用的IP地址形式,广播分为以下两种:
- 直接广播(Directed Broadcast)
- 本地广播(Local Broadcast)
二者在实现上的差别主要在于IP地址。直接广播的IP地址中除了网络地址外,其余主机地址全部设置成 1。例如,希望向网络地址 192.12.34 中的所有主机传输数据时,可以向 192.12.34.255 传输。换言之,可以采取直接广播的方式向特定区域内所有主机传输数据。
反之,本地广播中使用的IP地址限定为 255.255.255.255 。例如,192.32.24 网络中的主机向 255.255.255.255 传输数据时,数据将传输到 192.32.24 网络中所有主机。
数据通信中使用的IP地址是与 UDP 示例的唯一区别。默认生成的套接字会阻止广播,因此,只需通过如下代码更改默认设置。
int send_sock;
int bcast;
...
send_sock=socket(PF_INET,SOCK_DGRAM,0);
...
setsockopt(send_sock,SOL_SOCKET,SO_BROADCAST,(void*)&bcast,sizeof(bcast));
...
14.2.2 实现广播数据的 Sender 和 Receiver
下面是广播数据的 Sender 和 Receiver的代码:
news_sender_brd.c 程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30
void error_handling(char *message);int main(int argc, char *argv[])
{int send_sock;struct sockaddr_in broad_adr;FILE *fp;char buf[BUF_SIZE];int so_brd = 1;if (argc != 3){printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);exit(1);}send_sock = socket(PF_INET, SOCK_DGRAM, 0); //创建 UDP 套接字memset(&broad_adr, 0, sizeof(broad_adr));broad_adr.sin_family = AF_INET;broad_adr.sin_addr.s_addr = inet_addr(argv[1]);broad_adr.sin_port = htons(atoi(argv[2]));setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void *)&so_brd, sizeof(so_brd));if ((fp = fopen("news.txt", "r")) == NULL)error_handling("fopen() error");while (!feof(fp)) //如果文件没结束就返回0{fgets(buf, BUF_SIZE, fp);sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&broad_adr, sizeof(broad_adr));sleep(2);}fclose(fp);close(send_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}
news_receiver_brd.c 程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30
void error_handling(char *message);int main(int argc, char *argv[])
{int recv_sock;int str_len;char buf[BUF_SIZE];struct sockaddr_in adr;if (argc != 2){printf("Usage : %s <PORT>\n", argv[0]);exit(1);}recv_sock = socket(PF_INET, SOCK_DGRAM, 0);memset(&adr, 0, sizeof(adr));adr.sin_family = AF_INET;adr.sin_addr.s_addr = htonl(INADDR_ANY);adr.sin_port = htons(atoi(argv[1]));if (bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr)) == -1)error_handling("bind() error");while (1){//通过 recvfrom 函数接受数据。如果不需要知道传输数据的主机地址信息,可以向recvfrom函数的第5 6参数分贝传入 NULL 0str_len = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, NULL, 0);if (str_len < 0)break;buf[str_len] = 0;fputs(buf, stdout);}close(recv_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}
相关文章:

TCP/IP网络编程——多播与广播
完整版文章请参考: TCP/IP网络编程完整版文章 文章目录第 14 章 多播与广播14.1 多播14.1.1 多播的数据传输方式以及流量方面的优点14.1.2 路由(Routing)和 TTL(Time to Live,生存时间),以及加入组的办法14…...

K8S DNS解析过程和延迟问题
一、Linux DNS查询解析原理(对于调用glibc库函数gethostbyname的程序)我们在浏览器访问www.baidu.com这个域名,dns怎么查询到这台主机呢? 1、在浏览器中输入www.baidu.com域名,操作系统会先查找本地DNS解析器缓存&a…...

【JavaScript】js实现深拷贝的方法
前言 在js中我们想要实现深拷贝,首先要了解深浅拷贝的区别。 浅拷贝:只是拷贝数据的内存地址,而不是在内存中重新创建一个一模一样的对象(数组) 深拷贝:在内存中开辟一个新的存储空间,完完全全…...

RK3288 GPIO记录
1、引脚对应的GPIO 编号第一种 使用/sys/kernel/debug/gpio查询所有gpio引脚的基数第二种 cat /sys/class/gpio/gpiochip248/label对应的label就是GPIO引脚,例如下图GPIO8对应的基数就是2482、计算编号编号 基数 PIN脚如GPIO8的基数是248, GPIO8_A6的编…...

MongoDB介绍及使用教程
文章目录一、MongoDB介绍1. 什么是MongoDB2. 为什么要用MongoDB3. MongoDB的应用场景4. MongoDB基本概念二、MongoDB使用教程1.下载安装(Windows)2.MongoDB Conpass简单使用(选学)3.使用navicat连接MongoDB4.JAVA项目中使用MongoD…...

51单片机开发环境搭建 - VS Code 从编写到烧录
我安装并测试成功的环境: 操作系统:Windows 10 (22H2)单片机:STC89C52RCPython version: 3.7.6 在这之前,给51单片机写程序是用 Keil 5(编写编译)、STC-ISP(烧录),由于…...
python datetime、字符串和时间戳之间的相互转换12小时制和24小时制时间相互转化
文章目录1.字符串转datetime格式2.datetime转字符串3.时间戳转datetime格式4.datetime格式转时间戳5.应用:将12小时制的字符串转换为时间戳1.字符串转datetime格式 把字符串转换为datetime的格式 项目字符串的样子‘%m/%d/%Y %H:%M:%S’2/3/2023 15:30:20‘%m-%d-…...

百度百科词条怎么做?百度百科词条创建攻略分享
只要是想要将自己宣传出去的企业或是个人,都建议创建属于自己的百度百科词条,因为百度百科词条流量大、权重高、排名靠前,创建百度百科词条可以提高企业或是个人的知名度和口碑。 百度百科词条怎么做?每天都有用户在百度上搜索这…...

基于Hive的河北新冠确诊人数分析系统的设计与实现
项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…...

k8s二进制部署
目录 一、环境准备 常见的k8s部署方式 关闭防火墙 关闭selinux 关闭swap 根据规划设置主机名 在master添加hosts 将桥接的IPv4流量传递到iptables的链 时间同步 二、部署etcd集群 1、master节点部署 #查看证书的信息 上传etcd-cert.sh 和etcd.sh 到/opt/k8s/ 目录…...

Windows出现0xc00d36e5错误怎么办?
当我们使用Windows Media Player来播放视频文件时,可能会出现无法播放,并显示0xc00d36e5错误代码。该错误可能是因为Windows Media Player不支持视频格式、注册表项损坏、系统配置问题、第三方应用程序冲突等。下面将开始介绍0xc00d36e5错误的解决方法&a…...

Idea搭建Spring5.3.x源码阅读环境
1. 概述 Spring是一个轻量级Java开源框架,在Java项目开发过程中已经离不开Spring全家桶了,包括Spring、SpringBoot、SpringCloud等,学习好Spring基础源码也有助于更好在项目中使用Spring相关组件,在学习源码前需要搭建好源码学习…...

2.20jdbc
一.数据库编程的必备条件编程语言:java c c Python数据库 Oracle,MySQL,SQL Server数据库驱动包:不同的数据库,对应不同的编程语言提供了不同的数据库驱动包:MySQL提供了Java的驱动包mysqlconnector-java,需要就Java操作MySQL需要该驱动包二.Java的数据库编程JDBC,即…...

【代码随想录训练营】【Day19休息】【Day20】第六章|二叉树|654.最大二叉树|617.合并二叉树|700.二叉搜索树中的搜索|98.验证二叉搜索树
最大二叉树 题目详细:LeetCode.654 这道题在题目几乎就说明了解题的思路了: 创建一个根节点,其值为 nums 中的最大值;递归地在最大值左边的子数组上构建左子树;递归地在最大值右边的子数组上构建右子树;…...

华为云计算之容灾技术
容灾是物理上的容错技术,不是逻辑上的容错同步远程复制:主备距离≤200km,只有在主备设备上都写成功,才会告诉主机写成功,不会丢失数据异步远程复制:主备距离>200km,只要主设备上写成…...

React系列之Redux
1 Redux概述 Redux 是 JavaScript 状态容器,提供可预测化的状态管理。Redux中文文档 Redux 和react没有必然关系,redux可以应用于各种框架,包括jquery,甚至js都可以使用redux,只不过redux和react更加搭配。redux也推…...

最简单得方法解决TCP分包粘包问题
如何用最简单的方法解决TCP传输中的分包粘包问题? 首先需要说明一点,分包粘包等等一系列的问题并不是协议本身存在的问题,而是程序员在写代码的时候,没有搞清楚数据的边界导致的。 看个简单的例子,TCP客户端不断的向服…...

免费使用通配符域名证书
文章目录前言一、手动安装acme.sh操作1、安装acme.sh2、使用dns api自动续签二、宝塔自动操作【推荐】总结前言 之前个人站点一般都是使用阿里云免费单域名证书,虽然好用但是只有一年有效,到期只能手动重新申请,并且每次弄个子域名出来就要重…...

0基础成功转行Python自动化测试工程师,年薪30W+,经验总结都在这(建议收藏)
两年前的决定我觉得还是非常正确的,就是自学了python,然后学习了自动化测试、性能测试、框架、持续集成,同时也把前面的软件测试基础知识全部补全了。目前的收入还比较满意,月入2W(仅代表个人收入),13薪&am…...

MyBaits
MyBaitsMyBaits的jar包介绍MyBaits的入门案例创建实体java日志处理框架常用的日志处理框架Log4j的日志级别Mybatis配置的完善Mybatis的日志管理使用别名alias方式一方式二SqlSession对象下的常用API查询操作Mapper动态代理Mapper 动态代理规范查询所有用户根据用户ID查询用户Ma…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...