组播通信是一种基于UDP协议的网络通信方式,它允许发送方将消息同时传递给多个接收方。在组播通信中,发送方和接收方都会加入一个共同的组播组,这个组播组对应一个特定的IP地址,所有加入该组播组的主机都能够接收到发送方发送的消息。组播通信可以有效地减少网络流量和网络负载,因为在传统的点对点通信方式下,每个消息都需要单独传输到每个接收方,而在组播通信中,每个消息只需要传输一次,就可以同时传递给多个接收方。

在使用组播模式时,需要在套接字上使用setsockopt()函数来设置套接字的IP_MULTICAST_IF选项,指定本地主机的出站接口地址,用于发送组播数据包。此外,还可以设置IP_ADD_MEMBERSHIP选项,将套接字加入到一个特定的组播组中,以便接收该组播组中的数据包。

在使用组播模式时需要读者注意,组播模式需要使用特定的IP地址范围,如224.0.0.0~239.255.255.255,且需要确保组播组内的所有成员都在同一个网络中。同时,组播模式也不保证数据传输的可靠性,因为UDP本身就是无连接的协议,所以需要在应用程序中自行处理数据丢失或重复的情况。

14.5.1 服务端实现

先来实现服务端代码,首先我们定义一个端口号PORT=9999并定义好组名GROUP="225.1.2.3",接着通过调用两次setsockopt函数,第一次调用指定传入SO_REUSEADDR参数设置为组播模式,第二次调用指定传入IP_ADD_MEMBERSHIP用于设置组,经过两次设置服务端将被绑定到GROUP指定的组名上面,并在底部recvfrom循环等待数据包的到达,当数据包到达后则直接通过sendto发送一个消息给上线客户端。

#include <winsock.h>
#include <iostream> #pragma comment(lib, "wsock32.lib")
#define PORT 9999
#define GROUP "225.1.2.3" using namespace std; int main(int argc, char *argv[])
{
WSADATA wsaData;
struct sockaddr_in addr;
int fd;
struct ip_mreq mreq; // 初始化套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "初始化失败" << std::endl;
return 0;
} // 创建套接字 SOCK_DGRAM 采用UDP
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
std::cout << "套接字创建失败" << std::endl;
return 0;
} // 设置套接字为组播模式
u_int yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)
{
std::cout << "设置组播模式失败" << std::endl;
return 0;
} memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT); // 绑定套接字
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
std::cout << "绑定失败" << std::endl;
return 0;
} // 设置组播模式中的组信息
mreq.imr_multiaddr.s_addr = inet_addr(GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY); // 设置组
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
{
int err = GetLastError();
std::cout << "设置组失败: " << err << std::endl;
return 0;
} // 循环手法数据
while (1)
{
char recv_buffer[4096];
int addrlen = sizeof(addr);
int nbytes; // 接收组播数据
if ((nbytes = recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) &addr, (int *)&addrlen)) < 0)
{
std::cout << "接收数据包失败" << std::endl;
return 0;
}
recv_buffer[nbytes] = '\0';
std::cout << "接收组播数据包: " << recv_buffer << std::endl; // 发送组播数据包
char send_buffer[4096] = "server mesage";
sendto(fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr *) &addr, sizeof(addr));
} return 0;
}

14.5.2 客户端实现

在组播模式中客户端的修改部分很简单,仅仅只需通过socket(AF_INET, SOCK_DGRAM, 0)函数设置套接字为UDP模式,并填充组名即可,其他通信模式与UDP保持一致。

#include <winsock.h>
#include <iostream> #pragma comment(lib, "wsock32.lib")
#define PORT 9999
#define GROUP "225.1.2.3" using namespace std; int main(int argc, char *argv[])
{
WSADATA wsaData;
struct sockaddr_in addr;
int fd; // 初始化套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "初始化失败" << std::endl;
return 0;
} // 创建套接字 SOCK_DGRAM 采用UDP
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
std::cout << "套接字创建失败" << std::endl;
return 0;
} // 设置组播模式组信息
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(GROUP);
addr.sin_port = htons(PORT); // 循环
while (1)
{
// 发送组播数据包
char send_buffer[4096] = "Hello, World!";
if (sendto(fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
std::cout << "发送失败" << std::endl;
return 0;
} // 接收组播数据
int addrlen = sizeof(addr);
char recv_buffer[4096] = { 0 };
recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) &addr, (int *)&addrlen);
std::cout << "接收组播数据包: " << recv_buffer << std::endl;
Sleep(1000);
}
return 0;
}

读者可自行编译上述代码,运行一个服务端并运行多个客户端即可观察组播收发情况,如下图所示;

14.5 Socket 应用组播通信的更多相关文章

  1. IPv4组播通信原理

    2011-05-08 21:21:14 标签:组播 vin_do,vin_do学习笔记,笔记 休闲 职场 摘自网络,感谢原作者 摘要: 本文试图成为学习TCP/IP网络组播技术的入门材料.文中介绍了组 ...

  2. Python3组播通信编程实现教程(发送者+接收者)

    一.说明 1.1 标准组播解释 通信分为单播.多播(即组播).广播三种方式 单播指发送者发送之后,IP数据包被路由器发往目的IP指定的唯一一台设备的通信形式,比如你现在与web服务器通信就是单播形式 ...

  3. Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型

    Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...

  4. 使用TCP/IP的套接字(Socket)进行通信

    http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html 使用TCP/IP的套接字(Socket)进行通信 套接字Socket的引入 ...

  5. java socket实现全双工通信

    java socket实现全双工通信 单工.半双工和全双工的定义 如果在通信过程的任意时刻,信息只能由一方A传到另一方B,则称为单工. 如果在任意时刻,信息既可由A传到B,又能由B传A,但只能由一个方 ...

  6. Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信

    链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html 使用TCP/IP的套接字(Socket)进行通信 套接字Socke ...

  7. linux c使用socket进行http 通信,并接收任意大小的http响应(四)

    终于说到SOCKET 这里了.SOCKET进行http通信的实际就是利用socket将http请求信息发送给http服务器,然后再利用socket接收http响应. 由于本文与之通信的服务器是ip已知 ...

  8. linux c使用socket进行http 通信,并接收任意大小的http响应(三)

    使用socket进行http通信的时候,浏览器返回的响应经常不是固定长度的,有时候很大,有些时候又非常小,十分讨厌.如果仅仅只是为了接收一小段信息,设置一个十分大的缓存,这样又会十分浪费.而且经常更改 ...

  9. 一步一步学Silverlight 2系列(14):数据与通信之WCF

    一步一步学Silverlight 2系列(14):数据与通信之WCF   概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框 ...

  10. socket上http协议应用(使用socket进行http通信的例子,准备好报头以后,简单read/write就可以了)

    前几天看socket本有点晕, 好不容易弄明白了,才发现公司服务器用的是http的. 找了好久也没发现linux下直接用http的api, 不过今日偶然发现了使用socket进行http通信的例子, ...

随机推荐

  1. vi / vim 键盘图(清晰打印版,桌面背景好图)

    PDF File https://files.cnblogs.com/files/RioTian/vivim-graphical.zip?t=1704439837&download=true ...

  2. 关于 Jupyter 导出 PDF/Latex 格式报错的简单解决方法

    利用 Jupyter 提供的 Print Preview 功能,然后鼠标右键点击打印,就能导出PDF了,而且不会出问题,中文,图片都可以

  3. KB专题:区间DP专辑

    自从多校后心憔悴啊,发现DP还是太水了,有一场的区间DP竟然不会做,咳,果然是赤裸裸的水军. 花了几天时间写了几道区间DP的题目,大部分都是水题,然后和以前的合并起来就是KB区间DP这个8 + 1道题 ...

  4. 0x01 基本算法-位运算

    A题:a^b https://ac.nowcoder.com/acm/contest/996/A 题目描述 求 a 的 b 次方对 p 取模的值,其中 0 <= a,b,p <= 10^9 ...

  5. 【每日一题】40. 旅游 (树形DP解决树的最大独立集)

    补题链接:Here 算法涉及:树形DP寻找树上最大独立集 一开始想到是利用 树形DP 找树的直径问题,但这里由于可以利用走过的点衍生,所以不符合树的直径问题 查询了一下资料这道题是属于: 树的最大独立 ...

  6. 【每日一题】26.codeJan与旅行 (贪心)

    补题链接:Here 算法涉及:贪心 思路: 首先,我们处在p位置,显然要么向左走到相邻的城市,要么向右走走到相邻的城市. 有一个不会证明但观察到的结论,从这两个位置走的话,只有四种可能. 可能1:一直 ...

  7. 2017年第八届 蓝桥杯B组C/C++决赛题目

    部分题目示意图来自网络,所以会带水印 最后编辑时间: 2021年5月12日 统一声明 如果不写默认带有常用头文件 如果不表明主函数默认表示在 void solve(){} 默认使用 using nam ...

  8. SpringCloud学习 系列五、创建生产者和消费者验证微服务中心 Eureka的作用

    系列导航 SpringCloud学习 系列一. 前言-为什么要学习微服务 SpringCloud学习 系列二. 简介 SpringCloud学习 系列三. 创建一个没有使用springCloud的服务 ...

  9. 大数据(3)---HDFS客户端命令及java连接

    一.参数设置 之前有说到HDFS的备份数量和切块大小都是可以配置的,默认是备份3,切块大小默认128M 文件的切块大小和存储的副本数量,都是由客户端决定! 所谓的由客户端决定,是通过客户端机器上面的配 ...

  10. 【内核】深入分析内核panic(二)--内核中的少林扫地僧-NMI Watchdog Timer

    没有完美的代码 没有完美的人,更没有完美的代码.虽然教科书上说deadlock(死锁)多么不好不好,但是在现实生活中,很难把它完全消灭.假设不小心内核出现了deadlock,可能你得干瞪眼.CPU就在 ...