14.5 Socket 应用组播通信
组播通信是一种基于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 应用组播通信的更多相关文章
- IPv4组播通信原理
2011-05-08 21:21:14 标签:组播 vin_do,vin_do学习笔记,笔记 休闲 职场 摘自网络,感谢原作者 摘要: 本文试图成为学习TCP/IP网络组播技术的入门材料.文中介绍了组 ...
- Python3组播通信编程实现教程(发送者+接收者)
一.说明 1.1 标准组播解释 通信分为单播.多播(即组播).广播三种方式 单播指发送者发送之后,IP数据包被路由器发往目的IP指定的唯一一台设备的通信形式,比如你现在与web服务器通信就是单播形式 ...
- Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
- 使用TCP/IP的套接字(Socket)进行通信
http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html 使用TCP/IP的套接字(Socket)进行通信 套接字Socket的引入 ...
- java socket实现全双工通信
java socket实现全双工通信 单工.半双工和全双工的定义 如果在通信过程的任意时刻,信息只能由一方A传到另一方B,则称为单工. 如果在任意时刻,信息既可由A传到B,又能由B传A,但只能由一个方 ...
- Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信
链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html 使用TCP/IP的套接字(Socket)进行通信 套接字Socke ...
- linux c使用socket进行http 通信,并接收任意大小的http响应(四)
终于说到SOCKET 这里了.SOCKET进行http通信的实际就是利用socket将http请求信息发送给http服务器,然后再利用socket接收http响应. 由于本文与之通信的服务器是ip已知 ...
- linux c使用socket进行http 通信,并接收任意大小的http响应(三)
使用socket进行http通信的时候,浏览器返回的响应经常不是固定长度的,有时候很大,有些时候又非常小,十分讨厌.如果仅仅只是为了接收一小段信息,设置一个十分大的缓存,这样又会十分浪费.而且经常更改 ...
- 一步一步学Silverlight 2系列(14):数据与通信之WCF
一步一步学Silverlight 2系列(14):数据与通信之WCF 概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框 ...
- socket上http协议应用(使用socket进行http通信的例子,准备好报头以后,简单read/write就可以了)
前几天看socket本有点晕, 好不容易弄明白了,才发现公司服务器用的是http的. 找了好久也没发现linux下直接用http的api, 不过今日偶然发现了使用socket进行http通信的例子, ...
随机推荐
- python像操作文件一样操作内存的模块 StringIO
io流(io stream) 流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插 ...
- 动作捕捉用于验证芭蕾舞动作对脑瘫儿童的作用 NOKOV度量动作捕捉
下肢杠杆力臂功能障碍(Lever Arm Dysfunction,LAD)是常见的导致脑瘫儿童步态异常的原因,如髋内旋.股骨和胫骨之间的旋转畸形以及足的内外翻畸形等,且都与年龄的增长呈正相关. 图 ...
- 【短道速滑六】古老的视频去噪算法(FLT_GradualNoise)解析并优化,可实现1920*1080 YUV数据400fps的处理能力。
这个好像没有啥对应的论文可以找到,在百度上搜索也能找到一些相关的资料,不过就直接是代码,可以看到其实来自于一个叫做DScaler的项目,在github上目前还能找到该项目的完整资料. 详见:https ...
- ChatExcel?
大家好,我是章北海mlpy 最近在浅学LangChain,在大模型时代,感觉这玩意很有前途. LangChain是一个开源的应用开发框架,目前支持Python和TypeScript两种编程语言. 它赋 ...
- CH#17C 舞动的夜晚(最大流+强连通分量)
舞动的夜晚 CH Round #17 描述 L公司和H公司举办了一次联谊晚会.晚会上,L公司的N位员工和H公司的M位员工打算进行一场交际舞.在这些领导中,一些L公司的员工和H公司的员工之间是互相认识的 ...
- # 0x54 动态规划-树形DP
A.没有上司的舞会 基础树形DP emmm,蒟蒻发现自己的DP太辣鸡了...所以来练练DP,这题的话实际上应该算是树DP的入门题吧,转移还是挺好想的. 每次在每个节点都会有个选择,就是选还是不选,如果 ...
- 【D3 API 中文手册】
https://blog.csdn.net/tianxuzhang/article/details/47067699?utm_medium=distribute.pc_relevant.none-ta ...
- LightOJ 1094
题意:就是求一个树的直径,也就是求任意两点的最大距离. 做法:跑两遍DFS,详见代码. #include<iostream> #include<cstdio> #include ...
- 机器学习-线性回归-损失函数+正则化regularization-06
目录 1. 为什么要加上正则项 2 L1稀疏 L2平滑 3. 代码1--L2正则 4 代码2--L2正则2 5. 代码3--l1正则 6. ElasticNet 1. 为什么要加上正则项 防止模型的过 ...
- 【rt-thread】Kconfig文件添加子Kconfig文件时是以顶级Kconfig所在目录为当前路径的
示例如下 顶级Kconfig文件所在目录 子级Kconfig文件所在目录 子级Kconfig文件添加次子级Kconfig文件,以顶级目录为当前路径依次写出次子级Kconfig文件所在目录