网络编程之多播
Posted oldmao_2000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程之多播相关的知识,希望对你有一定的参考价值。
文章目录
简介
单播数据只能发送给单个目的主机,一个发送方、一个接收方,两个主机间的通信不影响其他主机。广播数据是通过广播地址将数据发送给局域网上的所有主机,广播一般只在单个局域网中传播。
多播和广播一样也是将数据发送给多个主机,但仅将数据发送给属于相同多播组的主机,而且多播数据能通过路由器进行传播。
IGMP
多播使用的协议是IGMP(Internet Group Management Protocol),该协议是IP协议簇的一个组成部分,可在IP首部的协议字段设置为2,标记为IGMP协议。IGMP共有三个版本:IGMPv1、IGMPv2、IGMPv3。
版本 | 加入多播组 | 离开多播组 | 多播源过滤 |
---|---|---|---|
IGMPv1 | √ | × | × |
IGMPv2 | √ | √ | × |
IGMPv3 | √ | √ | √ |
多播源过滤是指可设置接收多播数据的主机白名单。这个功能是IGMPv3才有的,Windows Vista及以上版本才支持IGMPv3。 |
多播地址
多播地址属于D类IP地址,前4位为固定的1110,剩余的28位用于标识多播组。
前4位 | 后28位 |
---|---|
1110 | 多播组标识 |
用十进制表示多播地址范围是:224.0.0.0~239.255.255.255。组播组可以是永久的也可以是临时的。 | |
224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用; | |
224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet; | |
224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效; | |
239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。 | |
固定的多播组地址是是永久的,它们的组员个数在任意时刻是变化的,甚至是0个;其他临时多播组则只有组员个数大于0时才存在。 |
RFC官方规定了一些固定的多播组地址:
多播地址 | 用途 |
---|---|
224.0.0.0 | 保留地址 |
224.0.0.1 | 子网所有组播主机,含网关 |
224.0.0.2 | 子网所有组播路由器 |
224.0.0.4 | DRMRP 路由器 |
224.0.0.5 | 所有OSPF的路由器 |
224.0.0.6 | OSPF指定路由器 |
224.0.0.10 | EIGRP 路由器 |
224.0.0.12 | DHCP服务器/中继器 |
224.0.1.1 | NTP 网络时间协议 |
组播相关结构体
https://docs.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-ip_mreq
typedef struct ip_mreq
IN_ADDR imr_multiaddr;
IN_ADDR imr_interface;
IP_MREQ, *PIP_MREQ;
成员①:多播组IP
成员②:本地IP地址
typedef struct ip_mreq_source
IN_ADDR imr_multiaddr;
IN_ADDR imr_sourceaddr;
IN_ADDR imr_interface;
IP_MREQ_SOURCE, *PIP_MREQ_SOURCE;
成员①:多播组IP
成员②:源地址黑/白名单
成员③:本地IP地址
多播实例
这里只有一台机器,但是仍然能够看出来和简单的单播不一样的地方,发送的目标是组播IP,接收的时候使用本地IP
发送
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<winsock2.h>
#include<ws2ipdef.h>
#include<stdio.h>
#pragma comment(lib, "ws2_32.lib")
//项目->属性->高级,字符集选择【使用多字符集】
int main()
WORD wVersionRequested = MAKEWORD(2, 2);//版本
WSADATA wsaDATA;
//打开网络库
if (WSAStartup(wVersionRequested, &wsaDATA) != 0)
printf("打开网络库失败!\\n");
return -1;
ip_mreq mreq;
int TTL = 8;
mreq.imr_interface.S_un.S_addr = inet_addr("127.0.0.1");//本地IP
mreq.imr_multiaddr.S_un.S_addr = inet_addr("234.2.3.4");//多播组IP
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//创建Socket句柄,多播只支持UDP
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&TTL, sizeof(TTL)) != 0)//设置TTL
printf("setsockopt设置TTL失败!\\n");
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return -1;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(ip_mreq)) != 0)//加入多播组
printf("setsockopt设置TTL失败!\\n");
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return -1;
struct sockaddr_in multiif;
multiif.sin_family = AF_INET;
multiif.sin_port = htons(9527);//用htons宏将整型转为端口号的无符号整型
multiif.sin_addr.S_un.S_addr = inet_addr("234.2.3.4");//使用多播IP作为目标IP
//multiif.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//相当于绑定到0.0.0.0
int i = 0;
char Sendbuf[0x100] = 0 ;
while (1)
sprintf_s(Sendbuf,"%d", i);//将自增量写入发送变量
i++;
//也可以用connect+send组合
if (sendto(sock, Sendbuf, sizeof(Sendbuf), 0, (const struct sockaddr*)&multiif, sizeof(sockaddr_in)) == SOCKET_ERROR)
int err = WSAGetLastError();//取错误码
printf("服务器sendto失败错误码为:%d\\n", err);
continue;
Sleep(1000);//休息1秒钟再发送
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return 0;
接收
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<winsock2.h>
#include<ws2ipdef.h>
#include<stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main()
WORD wVersionRequested = MAKEWORD(2, 2);//版本
WSADATA wsaDATA;
//打开网络库
if (WSAStartup(wVersionRequested, &wsaDATA) != 0)
printf("打开网络库失败!\\n");
return -1;
ip_mreq mreq;
int TTL = 8;
mreq.imr_interface.S_un.S_addr = inet_addr("127.0.0.1");//本地IP
mreq.imr_multiaddr.S_un.S_addr = inet_addr("234.2.3.4");//多播组IP
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//创建Socket句柄,多播只支持UDP
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&TTL, sizeof(TTL)) != 0)//设置TTL
printf("setsockopt设置TTL失败!\\n");
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return -1;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(ip_mreq)) != 0)//加入多播组
printf("setsockopt设置TTL失败!\\n");
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return -1;
struct sockaddr_in localif;
localif.sin_family = AF_INET;
localif.sin_port = htons(9527);//用htons宏将整型转为端口号的无符号整型
localif.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//使用多播IP作为目标IP
if (SOCKET_ERROR == bind(sock, (const struct sockaddr*)&localif, sizeof(localif)))
int err = WSAGetLastError();//取错误码
printf("bind失败错误码为:%d\\n", err);
closesocket(sock);//释放
WSACleanup();//清理网络库
return 0;
char Recvbuf[0x100] = 0 ;
int Recvlen = sizeof(localif);
while (1)
//用recv简单直接收取消息
if (recv(sock, Recvbuf, sizeof(Recvbuf), 0) == SOCKET_ERROR)
int err = WSAGetLastError();//取错误码
printf("recv失败错误码为:%d\\n", err);
continue;
//也可以用recvfrom,额外获取发送方IP地址
//struct sockaddr_in sa;
//int iSaLen = sizeof(sa);
//if (recvfrom(sock, Recvbuf, sizeof(Recvbuf), 0, (struct sockaddr*)&sa,&iSaLen) == SOCKET_ERROR)
//
// int err = WSAGetLastError();//取错误码
// printf("recv失败错误码为:%d\\n", err);
// continue;
//
//printf("%s\\n", inet_ntoa(sa.sin_addr));
printf("%s\\n", Recvbuf);
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return 0;
白名单多播源过滤法
使用ip_mreq_source 添加若干个多播源IP,形成白名单,不再接收其他多播源消息。setsockopt中的选项为IP_ADD_SOURCE_MEMBERSHIP
ip_mreq_source mreqs;
mreqs.imr_interface.S_un.S_addr = inet_addr("127.0.0.1");//本地IP
mreqs.imr_multiaddr.S_un.S_addr = inet_addr("234.2.3.4");//多播组IP
mreqs.imr_sourceaddr.S_un.S_addr = inet_addr("127.0.0.1");//白名单多播IP
if (setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char*)&mreqs, sizeof(ip_mreq_source)) != 0)//加入多播组
printf("setsockopt设置TTL失败!\\n");
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return -1;
如果要移除白名单中的多播IP,则setsockopt中的选项为IP_DROP_SOURCE_MEMBERSHIP
黑名单多播源过滤法
使用ip_mreq_source 添加若干个多播源IP,形成黑名单,不再接收黑名单中多播源消息。setsockopt中的选项为IP_ADD_BLOCK_SOURCE。
取消黑名单使用的选项为:IP_UNBLOCK_SOURCE
黑名单中的多播源需要存在多播组中,也就是先要用IP_ADD_MEMBERSHIP选项添加到多播组中的多播IP才能添加到黑名单中。
还有一种设置方式是使用WSAIoctl设置SIO_SET_MULTICAST_FILTER,该选项的数据类型如下:
https://docs.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-ip_msfilter
typedef struct ip_msfilter
IN_ADDR imsf_multiaddr;//多播地址
IN_ADDR imsf_interface;//本地地址
MULTICAST_MODE_TYPE imsf_fmode;//黑名单或者白名单
ULONG imsf_numsrc;//名单成员数量
IN_ADDR imsf_slist[1];//名单具体成员
IP_MSFILTER, *PIP_MSFILTER;
以上是关于网络编程之多播的主要内容,如果未能解决你的问题,请参考以下文章