九:多播和广播

1 多播

&emsp 多播(Multicast )方式的数据传输是基于UDP完成的。 因此,与UDP服务器端/客户端的实现方式非常接近。 区别在于, UDP数据传输以单一目标进行,而多播数据同时传递到加入(注册)特定组的大量主机。 换言之,采用多播方式时,可以同时向多个主机传递数据。

1.1 多播的数据传输方式及流量方面的优点

多播的数据传输特点如下:

  • 多播服务端针对特定多播组,只发送一次数据。
  • 即使只发送一次数据,但该组内的所有客户端都会接收数据。
  • 多播组数可在IP地址范围内任意增加。
  • 加入特定组即可接收发往该多播的数据。

  多播是D类IP地址(224.0.0.0~239.255.255.255),"加入多播组"可以理解为在D类IP地址中,我希望接收发往目标239.234.218.234的多播数据
  多播是基于UDP完成的,也就是说,多播数据包的格式与UDP数据包相同。不同的是,向网络发送一个多播数据包时,路由器将复制该数据包并传递到多个主机。多播需要借助路由器完成,如下图所示:

  不要觉得频繁复制同一数据包,会不利于网络流量,因为不会向同一区域发送多个相同的数据包。相当于羊村的100之羊,从很远的地方定了一批相同的订单,使用TCP/UDP需要送100次,但是使用多播,只需要送一次到羊村门口,然后村里驿站复制100份然后给小羊就行。基于这种特性,多播主要用于“多媒体数据的实时传输”。
  注意:虽然理论上可以完成多播通信,但不少路由器并不支持多播,或即便支持也因网络拥堵问题故意阻断多播。因此为了在不支持多播的路由器中完成多播通信,也会使用隧道技术。

1.2 路由和TTL,以及加入组的方法

  为了传递多播数据包,必须设置TTL(Time to Live),这是决定“数据包传递距离”的主要因素。TTL用整数表示,并且每经过一个路由器就减1,TTL变为0时,该数据包将无法传递被销毁。因此,TTL值设置过大将影响网络流量,设置国小会无法传递到目标,注意。
  TTL设置方法是通过此节:套接字可选项完成的。与TTL相关的协议层为IPPROTO_IP,选项名为IP_MULTICAST_TTL。具体设置如下:

int send_sock;
int time_live = 64;
...
send_sock = socket(PF_INET, SOCK_DGRAM, 0);
setsockopt(send_sock, IPPROTO, 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(FP_INET, SOCK_DGRAM, 0);
...
join_adr.imr_multiaddr.saddr = "多播组地址信息";
join_adr.imr_interface.saddr = "加入多播组的主机地址信息";
setsockopt(recv_sock, IPPROTO, IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));

ip_mreq的结构体定义如下:

struct ip_mreq
{struct in_addr imr_multiaddr;struct in_addr imr_interface;
}

1.3 实现多播Sender 和 Receiver

  多播中使用“发送者”和“接收者”替代服务端和客户端,此处Sender是多播数据的发送主体,Receiver是多播数据的发送主体,Receiver需要加入多播组接收数据。下面给出示例,示例背景如下:

  • Sender:向AAA组广播文件中保存的新闻消息
  • Receiver:接收传递到AAA组的新闻信息
    在这里插入图片描述

news_sender.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>#define TTL 64
#define BUF_SIZE 30void ErrorHandler(char* message) {fputs(message, stderr);fputc('\n', stderr);exit(1);
}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 <IP><PORT>\n", argv[0]);exit(1);}//多播通信基于UDPsend_sock = socket(PF_INET, SOCK_DGRAM, 0);//设置传输数据的目标地址信息memset(&mul_adr, 0, sizeof(mul_adr));mul_adr.sin_family = AF_INET;mul_adr.sin_addr.s_addr = inet_addr(argv[1]);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) {ErrorHandler("fopen() error");}//实际传输数据的区域。while (!feof(fp)) {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;
}

news_receiver.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>#define BUF_SIZE 30void ErrorHandler(char* message) {fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char* argv[]) {if (argc != 3) {printf("Usage : %s <GroupIP><PORT> \n", argv[0]);exit(1);}int recv_sock;int str_len;char buf[BUF_SIZE];struct sockaddr_in adr;struct ip_mreq join_adr;recv_sock = socket(PF_INET, SOCK_DGRAM, 0);memset(&adr, 0, sizeof(adr));adr.sin_family = AF_INET;adr.sin_addr.s_addr = inet_addr(INADDR_ANY);adr.sin_port = htons(atoi(argv[2]));if (bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr)) == -1) {ErrorHandler("bind error");}//初始化结构体ip_mreqjoin_adr.imr_multiaddr.s_addr = inet_addr(argv[1]); //初始化多播组地址join_adr.imr_interface.s_addr = htonl(INADDR_ANY);//加入多播组setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));while (1) {//不知道传输数据的主机地址信息,所以传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;
}

2 广播

  广播与多播都是一次性向多个主机发送数据,但是传输数据的范围有区别。多播即使在跨越不同网络的情况下,只要加入多播组就能接收数据。相反,广播只能向同一网络中的主机传输数据。

2.1 广播的理解及实现方法

  广播是向同一网络中所有主机传输数据的方法。广播也是基于UDP完成的,根据传输数据时使用的IP地址的形式,广播分为如下2种。

  • 直接广播
  • 本地广播

  二者在代码上的差别主要在于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网络中的所有主机。
  如何实现Sender和Receiver呢?实际上,如果不仔细观察广播示例中通信时使用的IP地址,则很难与UDP示例进行区分。也就是说,数据通信中使用的IP地址是与UDP示例的唯一区别。默认生成的套接字会阻止广播,因此只需要通过如下代码更改默认设置。

int send_sock;
int bcast = 1;
....
send_sock = socket(PF_INET, SOCK_DGRAM, 0);
....
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void*)&bcast, sizeof(bcast));
....

2.2 实现广播数据的Sender 和 Receiver

在这里插入图片描述
new_sender_brd.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUFF_SIZE 30void ErrorHandler(char* message) {fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char* argv[]) {if (argc != 3) {printf("Usage: %s <Boardcast IP> <PORT>\n", argv[0]);exit(1);}int send_sock = socket(PF_INET, SOCK_DGRAM, 0);struct sockaddr_in broad_addr;memset(&broad_addr, 0, sizeof(broad_addr));broad_addr.sin_family = AF_INET;broad_addr.sin_addr.s_addr = inet_addr(argv[1]);broad_addr.sin_port = htons(atoi(argv[2]));int bcast = 1;setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void*)&bcast, sizeof(bcast));FILE* fp;if((fp = fopen("news.txt", "r")) == NULL) {ErrorHandler("fopen() error");}char buf[BUFF_SIZE];while(!feof(fp)) {fgets(buf, BUFF_SIZE, fp);sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr*)&broad_addr, sizeof(broad_addr));sleep(2);}close(send_sock);return 0;
}

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 BUFF_SIZE 30void ErrorHandler(char* message) {fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char* argv[]) {if (argc != 2) {printf("Usage : %s <PORT> \n", argv[0]);exit(1);}int recv_sock;struct sockaddr_in adr;int str_len;char buf[BUFF_SIZE];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) {ErrorHandler("bind error");}while (1) {str_len = recvfrom(recv_sock, buf, BUFF_SIZE-1, 0, NULL, 0);if (str_len < 0) {break;}buf[str_len] = 0;fputs(buf, stdout);}close(recv_sock);return 0;
}
```

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

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

相关文章

嵌入式驱动学习第二周——Linux休眠唤醒

前言 这篇博客来聊一聊Linux系统的休眠与唤醒。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xff0c;一起讨论一起学习。现在关注就是老粉啦&#xff01; 目录 前言1. …

Truenas入门级教程

Truenas入门教程 前言&#xff1a;系统相关配置 采用I3 4160&#xff0c;采用了2块500G的硬盘&#xff0c;内存为8G&#xff0c;两个网卡只用了其中一个&#xff0c;系统安装的是core版本 硬件采用DELL3020MT机箱&#xff0c;自带3个SATA网口&#xff0c;后期网口不够&#…

-bash: unzip: 未找到命令的解决方案

遇到 -bash: unzip: 未找到命令 这样的错误信息&#xff0c;表示你的系统中没有安装 unzip 工具。unzip 是一个常用的解压工具&#xff0c;用于解压缩 .zip 文件。你可以通过系统的包管理器安装它。 根据你使用的 Linux 发行版&#xff0c;安装 unzip 的命令会有所不同。下面是…

C# SwinV2 Stable Diffusion 提示词反推 Onnx Demo

目录 介绍 效果 模型信息 项目 代码 下载 C# SwinV2 Stable Diffusion 提示词反推 Onnx Demo 介绍 模型出处github地址&#xff1a;https://github.com/SmilingWolf/SW-CV-ModelZoo 模型下载地址&#xff1a;https://huggingface.co/SmilingWolf/wd-v1-4-swinv2-tagg…

自动化测试之web自动化(Selenium)

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

飞桨AI框架安装和使用示例

飞桨AI框架安装和使用示例 飞桨PaddlePaddle是非常流行的国产AI框架&#xff0c;让我们一起来动手实践吧&#xff01; 安装 飞桨安装参考页面&#xff1a;https://www.paddlepaddle.org.cn/install/quick?docurl/documentation/docs/zh/install/pip/linux-pip.html 在这个安…

网络工程师笔记10 ( RIP / OSPF协议 )

RIP 学习路由信息的时候需要配认证 RIP规定超过15跳认定网络不可达 链路状态路由协议-OSPF 1. 产生lsa 2. 生成LSDB数据库 3. 进行spf算法&#xff0c;生成最有最短路径 4. 得出路由表

【uni-app小程序开发】实现一个背景色渐变的滑动条slider

最近做的一个用uni-app+vue2开发的微信小程序项目中要实现一个滑动进度控制条,如下图所示: 1. 滑动条需要渐变背景色 2. 滑块的背景色需要与当前位置滑动条的背景色一致(动态改变) 碰到这样的需求,我当然先是看看官方提供的slider组件和uView里的u-slider组件能不能满足…

HarmonyOS云端一体化组件之AGC应用管理

&#xff08;可选&#xff09;在AGC控制台创建同包名应用 如创建工程时&#xff0c;发现尚未在AGC控制台创建与工程包名相同的应用&#xff0c;可进行补充创建。 1.点击界面提示内的“AppGallery Connect”&#xff0c;浏览器打开AGC控制台“我的项目”页面。 2.点击选择您希…

sql高级

sql高级 SQL SELECT TOP 子句 SELECT TOP 子句用于规定要返回的记录的数目。 SELECT TOP 子句对于拥有数千条记录的大型表来说&#xff0c;是非常有用的。 **注意:**并非所有的数据库系统都支持 SELECT TOP 语句。 MySQL 支持 LIMIT 语句来选取指定的条数数据&#xff0c; O…

万字长文讲解Golang pprof 的使用

往期好文推荐 ⭐️⭐️⭐️: # golang pprof 监控系列(1) —— go trace 统计原理与使用 # golang pprof监控系列&#xff08;2&#xff09; —— memory&#xff0c;block&#xff0c;mutex 使用 # golang pprof 监控系列(3) —— memory&#xff0c;block&#xff0c;mute…

数字孪生10个技术栈:数据采集的八种方式

大家好&#xff0c;我是贝格前端工场&#xff0c;上期讲了数字孪生10个技术栈&#xff08;总括&#xff09;:概念扫盲和总体介绍&#xff0c;获得了大家的热捧&#xff0c;本期继续分享技术栈&#xff0c;大家如有数字孪生或者数据可视化的需求&#xff0c;可以联络我们。 一、…