组播:用于对一组特定的主机进行通信,且这个特定的组内主机可以动态添加和删除多台主机,组内所有主机收到相同一份数据副本
组播地址
组播依赖于D类地址,范围从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
为本地管理组播地址,仅在特定的本地范围内有效。
组播属性设置
属性 | 说明 |
---|---|
IP_ADD_MEMBERSHIP | 加入指定的组播 |
IP_DROP_MEMBERSHIP | 退出指定的组播 |
IP_MULTICAST_IF | 设置组播中发送数据报文的接口 |
IP_MULTICAST_TTL | 设置组播中数据报文的生存时间(TTL),默认为1 |
IP_MULTICAST_LOOP | 设置组播中数据报文的副本是否回传 |
组播Demo
发送端
- 创建udpsocket
- 设置组播地址
- 发送数据
void muticast_sender()
{
const char* GROUP_IP = "239.0.0.1";
const int GROUP_PORT = 23888;
//创建套接字
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
//设置组播地址
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = inet_addr(GROUP_IP);
addr.sin_port = htons(GROUP_PORT);
while (true)
{
std::string msg = "muticast mesage";
if (sendto(sock, msg.c_str(), msg.size(), 0, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
std::cout << "muticast message failed" << std::endl;
break;
}
std::cout << "send muticast message ok" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
}
}
组播数据接收到
- 创建udpsocket
- 绑定组播端口 bind
- 设置组播属性,eg:IP_MULTICAST_LOOP ,IP_MULTICAST_TTL
- 加入组播
- 接收数据
void muticast_recever()
{
const char* GROUP_IP = "239.0.0.1";
const int GROUP_PORT = 23888;
//创建套接字
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
//绑定组播端口
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(GROUP_PORT);
int nret = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
if (SOCKET_ERROR == nret)
{
std::cout << "Failed to bind socket" << std::endl;
return;
}
int loop = 1;
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loop, sizeof(loop)) == -1)
{
std::cout << "Failed to setsockopt: IP_MULTICAST_LOOP" << std::endl;
return;
}
//多网卡,加入组播
for (auto& adapter_item:vec_adapter)
{
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(GROUP_IP);
//::inet_pton()
inet_pton(AF_INET, adapter_item.ip.c_str(), &mreq.imr_interface.s_addr);
//mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == SOCKET_ERROR)
{
DWORD dwErrcode = WSAGetLastError();
XLOGE("[%s]Failed to join multicast group,errcode:%d", adapter_item.ip.c_str(),dwErrcode);
}
else
{
XLOGI("[%s]join multicast group", adapter_item.ip.c_str());
}
}
// 接收消息
while (true)
{
char buffer[1024];
struct sockaddr_in senderAddr;
int senderAddrLen = sizeof(senderAddr);
int numBytes = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&senderAddr, &senderAddrLen);
if (numBytes == SOCKET_ERROR) {
std::cerr << "Failed to receive message" << std::endl;
return;
}
buffer[numBytes] = '\0';
std::cout << "Received message from " << inet_ntoa(senderAddr.sin_addr) << ": " << buffer << std::endl;
}
}
问题1:加入组播的时候遇见错误10042?
库导致的,取消ws2_32.lib,引入wsock32.lib,问题解决。
参考博客:https://blog.csdn.net/wmx313880747/article/details/39930049
问题2:多网卡?
需要加所有的网卡ip都加入组播
参考博客: https://blog.csdn.net/u012134942/article/details/109231666?spm=1001.2014.3001.5506
####问题排查
Windows 查看网卡是否加入多播组
netsh interface ipv4 show joins
查看绑定关系