【TCP/IP】多播 - 定义、原理及编程实现 (TTL、多播组、多播消息)

目录

多播

多播的原理

多播的数据传输时的特点

TTL 的概念

TTL 和 多播组的配置方法

多播的编程与实现

发送者

接收者


多播

        多播是一种介于单播和广播通信之间的技术方式,可以将发送者所需要发送的数据包分别发送给分散在不同子网中的一组接收者。

多播的原理

        多播的基础概念是“组”。一个多播组(multicast group)就是一组希望接收特定数据流的接收者,这个组没有物理或者地理的边界:组内的主机可位于互联网或者专用网络的任何地方。

        多播组中的每个节点被称为多播组成员(multicastgroupmember)。多播的数据传输协议基于UDP完成。采用多播方式时,可以同时向多个主机传递数据。

多播的数据传输时的特点

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

        多播组的地址属于D类,即 224.0.0.0 ~ 239.255.255.255在发送多播数据包时(路由器得支持这项功能),需要有机器加入到多播组中以接收发来的数据包,同时路由器担负起将该数据包复制并传递到多个主机中的任务。如下图所示:

TTL 的概念

        传输多播数据包时,需要给程序设置TTL(TIme to Live 生存时间),这是决定数据包能否及时准确到达目标点的关键参数。

        TTL用整数表示,每经过1个路由器该数值便会减1。当TTL变为0时,该数据包将无法再被传递,作销毁处理。因此,在TTL的值上需要合理设置,过大会影响网络流量,过小将无法将数据包及时传递到目标。

TTL 和 多播组的配置方法

        在编程中,我们可以实现对 TTL 的设置。TTL相关的协议层为IPPROTO_IP,选项名为IP_MULTICAST_TTL,通过使用setsocketopt这个函数进行设置。

        代码如下:

int sock;
int ttl = 64;sock = socket(PF_INET, SOCK_DGRAM, 0);
setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof(ttl));

        同样,加入到多播组也是通过 setsocketopt 函数完成。多播组加入的协议层为IPPROTO_IP,选项名为IP_ADD_MEMBERSHIP。 

        代码如下:

int recv_sock;
struct ip_mreq groupjoin_adr;recv_sock = socket(PF_INET, SOCK_DGRAM, 0);join_adr.imr_multiaddr.s_addr = "多播组的地址";
join_adr.imr_interace.s_addr = "加入多播组的主机地址";
setsockopt(recv_sock , IPPROTO_IP , IP_ADD_MEMBERSHIP , (void*) & groupjoin_adr), sizeof(groupjoin_adr));

        其中 ip_mreq 结构体,定义如下:

struct ip_mreq{/* 欲加入的多播组的地址.  */struct in_addr imr_multiaddr;/* 所属主机的IP地址. 可以使用INADDR_ANY  */struct in_addr imr_interface;};

多播的编程与实现

        多播中区分 发送者(Sender)接收者(Receiver)。发送者指的是发送多播数据的主体,接收者指的是位于多播组中的欲接收多播数据的主体。

发送者

#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 1024void Sender_message(char *message)
{puts(message);exit(1);
}int main(int argc, char *argv[])
{int send_sock;struct sockaddr_in mul_addr;int time2live = TTL;FILE *fp;char buf[BUF_SIZE];send_sock = socket(PF_INET, SOCK_DGRAM, 0);memset(&mul_addr, 0, sizeof(mul_addr));mul_addr.sin_family = AF_INET;mul_addr.sin_addr.s_addr = inet_addr(argv[1]); // 多播地址mul_addr.sin_port = htons(atoi(argv[2]));	   // 多播端口号setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&time2live, sizeof(time2live));fp = fopen(argv[3], "r");if (fp == NULL){Sender_message((char*)"file open error");}while (!feof(fp)) /* 发送数据 */{fgets(buf, BUF_SIZE, fp);sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&mul_addr, sizeof(mul_addr));}fclose(fp);close(send_sock);return 0;
}

接收者

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 1024//报错消息发送
void Sender_message(char *message)
{puts(message);exit(1);
}int main(int argc, char *argv[])
{int recv_sock;int str_len;char buf[BUF_SIZE];struct sockaddr_in addr;struct ip_mreq join_addr;recv_sock = socket(PF_INET, SOCK_DGRAM, 0);memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port = htons(atoi(argv[2]));if (bind(recv_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1){Sender_message((char*)"bind error");}join_addr.imr_multiaddr.s_addr = inet_addr(argv[1]);join_addr.imr_interface.s_addr = htonl(INADDR_ANY);setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_addr, sizeof(join_addr));while (1){// 接收多播数据 其中第五、第六个参数在不知道主机地址时可设为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;
}

运行结果

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

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

相关文章

Pytorch数据类型Tensor张量操作(操作比较全)

文章目录 Pytorch数据类型Tensor张量操作一.创建张量的方式1.创建无初始化张量2.创建随机张量3.创建初值为指定数值的张量4.从数据创建张量5.生成等差数列张量 二.改变张量形状三.索引四.维度变换1.维度增加unsqueeze2.维度扩展expand3.维度减少squeeze4.维度扩展repeat 五.维度…

8.6 socket套接字及TCP的实现框架

socket套接字 目录 socket套接字 体系结构的两种形式 几种常见的网络编程接口 socket套接字 socket常用API介绍 socket套接字 三元组【IP地址&#xff0c;端口&#xff0c;协议】 地址族结构体 套接字类型 TCP通信的实现过程 体系结构的两种形式 网络的体系结构 (N…

Vue3:计算属性、监听器

computed 计算属性 计算属性是指 基于现有状态派生 (演变) 出新的状态&#xff0c;现有状态发生变化&#xff0c;派生状态重新计算。 computed 接收回调函数作为参数&#xff0c;基于回调函数中使用的响应式数据进行计算属性的创建&#xff0c;回调函数的返回值就是基于现有状态…

C/C++内存管理

Lesson5–C/C内存管理 【本节目标】 1.C/C内存分布 2.C语言中动态内存管理方式 3.C中动态内存管理方式 4.operator new与operator delete函数 5.new和delete的实现原理 6.定位new表达式 7.常见面试题 C/C内存分布 先看一段C语言代码和相关问题 int globalVar 1; static in…

Spring Boot 如何使用 Log4j2 进行日志记录

Spring Boot 如何使用 Log4j2 进行日志记录 在开发 Java 应用程序时&#xff0c;日志记录是非常重要的一环。Spring Boot 提供了多种日志输出方式&#xff0c;其中 Log4j2 是一种比较常用的日志框架。本文将介绍如何在 Spring Boot 应用程序中使用 Log4j2 进行日志记录。 为什…

解决Tomcat控制台窗口输出乱码问题

由于编码的问题&#xff0c;tomcat的控制台窗口输出的都是中文乱码&#xff0c;这明显是编码格式导致的&#xff0c;只要找到对应的编码格式修改一下就好了&#xff0c; 由于我的服务器编码是GBK&#xff0c;所有只需把输出的编码修改为GBK就行了。 936就是GBK编码。找到tomca…

相机去畸变

1. 背景 在做图像感知工作过程中会遇到需要处理相机畸变的情况&#xff0c;如SLAM、3D重建等&#xff0c;则需要了解一些常见相机模型的成像过程&#xff0c;以及依据成像过程实现去除相机成像的畸变。 注意&#xff1a;这篇文章并不涉及太多相机参数畸变原理&#xff0c;更多…

使用亮数据Bright Data解决出境电商问题

目录 一、出境电商的困境和问题1、困境一&#xff1a;获取准确的市场数据&#xff08;1&#xff09;数据的时效性和可靠性&#xff08;2&#xff09;数据的全面性和多样性&#xff08;3&#xff09;数据的实时更新和持续监测 2、困境二&#xff1a;克服地域限制和语言障碍&…

我准备蓝桥杯的这一年

我准备蓝桥杯的这一年 文章目录 我准备蓝桥杯的这一年起步和目标确定渐入佳境焦虑疲惫&#xff0c;一天又一天国赛我来力总结 我将我这段 流水账分为四个阶段。谨以此文&#xff0c;祭奠我这一年来的焦虑、白发~ &#xff0c;最终也取得了预期的成绩。不知未来再看此章会作何感…

PHP 人才信息与招聘系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 人才信息与招聘系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为PHP APACHE&#xff0c;数据 库为mysql5.0&#xff0c;使用php语言开发。…

Postman设置断言

目录 前言&#xff1a; 一、断言的定义 二、Postman断言的语法 三、Postman中chai.js断言常用语法 前言&#xff1a; 在进行API测试时&#xff0c;断言是一项重要的功能。它能帮助我们验证接口的响应是否符合预期结果&#xff0c;从而确保API的正确性和可靠性。在Postman中…

科技资讯|苹果新专利曝光:手势增强用户的交互体验

根据美国商标和专利局&#xff08;USPTO&#xff09;公示的最新清单&#xff0c;苹果公司获得了一项编号为 US 20230195237 A1 的专利&#xff0c;展示了使用手势导航用户界面的交互体验。 苹果这项专利涉及 iPhone、iPad、Apple Watch 和 Mac&#xff0c;使用屏幕生成组件和…