[C++ 网络协议] 多播与广播

目录

[1. 多播](#1. 多播)

[1.1 多播的使用情形](#1.1 多播的使用情形)

[1.2 多播的原理](#1.2 多播的原理)

[1.3 如何实现多播](#1.3 如何实现多播)

[1.4 多播的代码实现](#1.4 多播的代码实现)

[2. 广播](#2. 广播)

[2.1 广播与多播的区别](#2.1 广播与多播的区别)

[2.2 广播的分类](#2.2 广播的分类)

[2.3 实现广播](#2.3 实现广播)


1. 多播

1.1 多播的使用情形

考虑一种情形,你要向10000名用户发送数据,此时如果用TCP提供服务,则需要维护10000个套接字连接,如果用UDP提供服务,则也需要进行10000次数据传输。像这样,在这总情况下,就可以使用多播技术来解决问题。所以一般多播常用于多媒体数据的实时传输

1.2 多播的原理

多播是基于UDP协议传输的。但又与UDP有一些不同,不同之处在于,UDP数据传输是以单一目标进行的,而多播则会将数据同时传递到加入(注册)多播组的大量主机。

其中,多播组是一种D类IP地址(224.0.0.0~239.255.255.255),加入多播组,可以理解为在D类IP地址中,我希望接收发往目标239.255.255.255的多播数据。

其原理如图:

多播数据包的格式与UDP数据包相同,但多播数据包在传输过程中时,路由器会复制该多播数据包并传递到多个主机。由此,主机只需要发送一次数据包,多个主机就能接受到,而无需一个数据包发多次。不像UDP或TCP,n个主机要接受数据包,就得传输n次。

1.3 如何实现多播

实现多播需要:

1.传递数据包的主机需要设置TTL(Time to Live,生存时间),TTL是决定数据包传送距离的主要因素,TTL用整数表示,每经过一个路由器就减1,直到TTL变为0时,数据包就无法再传输,只能销毁。因此TTL的值设置过大会影响网络流量,但过小就无法传递到目标。

2.接收数据包的主机需要加入多播组

上述两个条件的设置,用套接字可选项来完成。

|-------|------------|-------------------|
| 条件 | 协议层 | 可选项 |
| 设置TTL | IPPROTO_IP | IP_MULTICAST_TTL |
| 加入多播组 | IPPROTO_IP | IP_ADD_MEMBERSHIP |

1.4 多播的代码实现

设置TTL:

cpp 复制代码
int time_to_live=64;
setsockopt(senderfd,IPPROTO_IP,IP_MULTICAST_TTL,(void*)&time_to_live,sizeof(time_to_live);

加入多播组:

cpp 复制代码
ip_mreq join_adr;
join_adr.imr_multiaddr=inet_addr("要加入的多播组IP地址");
join_adr.imr_interface=htonl("加入该组的套接字所属主机的IP地址");

setsockopt(recvfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(void*)&join_adr,sizeof(join_adr));
cpp 复制代码
struct ip_mreq
{
    struct in_addr imr_multiaddr;    //要加入的多播组IP地址
    struct in_addr imr_interface;    //加入该组套接字所属主机IP
}

其中,imr_interface可以用INADDR_ANY

Sender:

cpp 复制代码
#include<iostream>
#include<cstring>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>

int main()
{
    int senderfd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
    if(senderfd==-1)
    {
        std::cout<<"socket fail!"<<std::endl;
    }

    int ttl=64;
    int res=setsockopt(senderfd,IPPROTO_IP,IP_MULTICAST_TTL,(void*)&ttl,sizeof(ttl));
    if(res==-1)
    {
        std::cout<<"setsockopt fail!"<<std::endl;
    }

    std::string strIp;
    std::cout<<"请输入要发往的多播IP地址:";
    std::cin>>strIp;

    sockaddr_in senderAddr;
    senderAddr.sin_family=AF_INET;
    senderAddr.sin_addr.s_addr=inet_addr(strIp.c_str());
    senderAddr.sin_port=htons(9130);

    std::cout<<"请输入你要发送的内容:";
    char buff[1024];
    std::cin>>buff;
    int sendLen;
    sendto(senderfd,buff,sizeof(buff),0,(sockaddr*)&senderAddr,sizeof(senderAddr));
    close(senderfd);
    return 0;
}

Recv:

cpp 复制代码
#include<iostream>
#include<cstring>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>

int main()
{
	int recvSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (recvSocket == -1)
	{
		std::cout << "socket fail!" << std::endl;
	}

	sockaddr_in recvAddr;
	recvAddr.sin_family = AF_INET;
	recvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	recvAddr.sin_port = htons(9130);
	if (-1 == bind(recvSocket, (sockaddr*)&recvAddr, sizeof(recvAddr)))
	{
		std::cout << "bind fail!" << std::endl;
	}
	
	std::string strIp;
	std::cout << "请输入要加入的多播IP地址:";
	std::cin >> strIp;

	ip_mreq join_adr;
	join_adr.imr_multiaddr.s_addr = inet_addr(strIp.c_str());
	join_adr.imr_interface.s_addr = htonl(INADDR_ANY);
	int res=setsockopt(recvSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));
	if (res ==-1)
	{
		std::cout << "setsockopt fail!" << std::endl;
	}

	char buff[1024];
	recvfrom(recvSocket, buff, sizeof(buff), 0, NULL, 0);    //因为此套接字是已连接UDP套接字,所以无需再进行绑定
	std::cout <<"接收到的多播信息:" << buff << std::endl;

	close(recvSocket);
	return 0;
}

运行结果:

Sender:

Recv:

注意:

1.发送方和接收方的端口号要一致

2.在这里接收方要先于发送方运行,因为多播属于广播的范畴,如果接收方延后,则会接收不到信息。

3.Windows里设置TTL,需要加上头文件#include<ws2tcpip.h>,因为IP_MULTICAST_TTL声明在这个头文件里。

2. 广播

2.1 广播与多播的区别

广播与多播的唯一区别是,广播只能向同一网络中的主机传输数据,而多播是可以跨越不同网络,只要加入多播组就能接收到数据的。

2.2 广播的分类

广播分为:直接广播、本地广播。

两者之间的差别主要是在于IP地址

直接广播的IP地址除了网络地址外,其余主机地址全部设置为1,。例如,希望向网络地址为192.12.32中的所有主机传输数据,则可以向192.12.32.255传输。换言之,直接广播就是可以向特定区域内所有主机传输数据。

本地广播的IP地址限定为255.255.255.255。例如,位于192.32.24网络中的主机向255.255.255.255传递数据时,数据将传递到这个网路中的所有主机上。换言之,本地广播就是只能向本地网络区域内所有主机传输数据。

2.3 实现广播

广播的实现需要:

|------------|--------------|-------------|
| 协议层 | 套接字可选项 | 值 |
| SOL_SOCKET | SO_BROADCAST | 0【关闭】/1【开启】 |

cpp 复制代码
int bcast=1;
setsockopt(send_sock,SOL_SOCKET,SO_BROADCAST,(void*)&bcast,sizeof(bcast));

广播的代码实现和多播没有什么区别,只需要把上述代码里套接字可选项改为SO_BROADCAST即可,然后在运行时,输入指定的IP地址(直接广播输入:xxx.xxx.xxx.255,本地广播输入:255.255.255.255)即可。

相关推荐
不想编程小谭2 分钟前
力扣LeetCode: 2506 统计相似字符串对的数目
c++·算法·leetcode
哑巴语天雨31 分钟前
前端面试-网络协议篇
websocket·网络协议·http·面试·https
曼巴UE51 小时前
UE5.3 C++ TArray系列(一)
开发语言·c++·ue5
阿巴~阿巴~2 小时前
多源 BFS 算法详解:从原理到实现,高效解决多源最短路问题
开发语言·数据结构·c++·算法·宽度优先
ktkiko112 小时前
Websocket——心跳检测
网络·websocket·网络协议
CoderCodingNo3 小时前
【GESP】C++二级真题 luogu-b3924, [GESP202312 二级] 小杨的H字矩阵
java·c++·矩阵
刃神太酷啦3 小时前
堆和priority_queue
数据结构·c++·蓝桥杯c++组
Heris993 小时前
2.22 c++练习【operator运算符重载、封装消息队列、封装信号灯集】
开发语言·c++
----云烟----3 小时前
C/C++ 中 volatile 关键字详解
c语言·开发语言·c++
小梁不秃捏3 小时前
HTTP 常见状态码技术解析(应用层)
网络·网络协议·计算机网络·http