IP多播

                      1   多播地址                    

IP多播地址采用D类IP地址确定多播的组,地址范围是224.0.0.0 到 239.255.255.255.

                       2 组管理协议(IGMP)              

两个多播节点之间的所有路由器必须支持IGMP协议

任何没有开启IGMP的路由器仅简单的丢弃接收到的多播数据

                      3   使用IP多播                        

1     加入离开组  

     IP_ADD_MEMBERSHIP 和 IP_DROP_MEMBERSHIP

下面的代码展示了如何 加入组:

    ip_mreq    mcast;
    mcast.imr_interface.S_un.S_addr = INADDR_ANY;
    mcast.imr_multiaddr.S_un.S_addr = ::inet_addr("234.5.6.7"); // 多播地址为234.5.6.7 
  ::setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast));

下面的代码显示了如何 退出组

    ip_mreq    mcast;
    mcast.imr_interface.S_un.S_addr = INADDR_ANY;
    mcast.imr_multiaddr.S_un.S_addr = ::inet_addr("234.5.6.7"); // 多播地址为234.5.6.7 
  ::setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&mcast, sizeof(mcast));

2     接收多播数据    

主机在接收IP多播数据之前,必须成为IP多播组的成员。为了接收发送到特定端口的多播封包,有必要绑定到那个本地端口,而不是显示的指定本地地址

如果套接字使用SO_REUSEADDR选项,就可以不止一个进程可以绑定到UDP端口

如下代码所示:

    BOOL bReuse = TRUE;
    ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(BOOL));

如此一来,每个来到这个共享端口的多播或者广播UDP封包都会发送给所绑定此端口的套接字

下面是接收多播封包的代码:

void main()
{
    SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);

    // 允许其它进程使用绑定的地址
    BOOL bReuse = TRUE;
    ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(BOOL));


    // 绑定到4567端口
    sockaddr_in si;
    si.sin_family = AF_INET;
    si.sin_port = ::ntohs(4567);
    si.sin_addr.S_un.S_addr = INADDR_ANY;
    ::bind(s, (sockaddr*)&si, sizeof(si));
    
    // 加入多播组
    ip_mreq    mcast;
    mcast.imr_interface.S_un.S_addr = INADDR_ANY;
    mcast.imr_multiaddr.S_un.S_addr = ::inet_addr("192.168.0.1");  // 多播地址为234.5.6.7
    ::setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast));


    // 接收多播组数据
    printf(" 开始接收多播组上的数据... \n");
    char buf[1280];
    int nAddrLen = sizeof(si);
    while(TRUE)
    {
        int nRet = ::recvfrom(s, buf, strlen(buf), 0, (sockaddr*)&si, &nAddrLen);
        if(nRet != SOCKET_ERROR)
        {
            buf[nRet] = '\0';
            printf(buf);
        }
        else
        {
            int n = ::WSAGetLastError();
            break;
        }
    }
}

3   带源地址的IP多播      

带源地址的IP多播允许加入组时,指定要接收哪些成员的数据

1 包含方式:指定N个有效的源地址,套接字仅接收来自这些源地址的数据

2 排除方式:指定N个有效的源地址,套接字将接受这些源地址之外的数据

    SOCKET    s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    // 本地接口
    SOCKADDR_IN    localif;
    localif.sin_family = AF_INET;
    localif.sin_port   = htons(5150);
    localif.sin_addr.s_addr = htonl(INADDR_ANY);
    ::bind(s, (SOCKADDR *)&localif, sizeof(localif));
    
    // 设置ip_mreq_source结构
    struct ip_mreq_source mreqsrc;
    mreqsrc.imr_interface.s_addr = inet_addr("192.168.0.46");
    mreqsrc.imr_multiaddr.s_addr = inet_addr("234.5.6.7");
    
    
    // 添加源地址218.12.255.113
    mreqsrc.imr_sourceaddr.s_addr = inet_addr("218.12.255.113");
    ::setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqsrc, sizeof(mreqsrc));
    // 添加源地址
    mreqsrc.imr_sourceaddr.s_addr = inet_addr("218.12.174.222");
    ::setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqsrc, sizeof(mreqsrc));

移除地址可以使用IP_DROP_MEMBERSHIP选项

全部试验源码:

sender.cpp:

///////////////////////////////////
// sender.cpp文件

#include "initsock.h"
#include "stdio.h"
#include <windows.h>

CInitSock theSock;

void main()
{
    SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);
    // 有效SO_BROADCAST选项
    BOOL bBroadcast = TRUE;
    ::setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL));

    // 设置广播地址,这里的广播端口号(电台)是4567
    SOCKADDR_IN bcast;
    bcast.sin_family = AF_INET;
    bcast.sin_addr.s_addr =  ::inet_addr("255.255.255.255");
    bcast.sin_port = htons(4567);

    // 发送广播
    char sz[] = "this is xingoo 123. \r\n";
    while(TRUE)
    {
        ::sendto(s, sz, strlen(sz), 0, (sockaddr*)&bcast, sizeof(bcast));
        ::Sleep(1000);
    }
}

recv.cpp:

#include "Initsock.h"

#include <stdio.h>
#include <windows.h>
#include <Ws2tcpip.h>



// 初始化Winsock库
CInitSock theSock;

void main()
{
    SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);

    // 允许其它进程使用绑定的地址
    BOOL bReuse = TRUE;
    ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(BOOL));


    // 绑定到4567端口
    sockaddr_in si;
    si.sin_family = AF_INET;
    si.sin_port = ::ntohs(4567);
    si.sin_addr.S_un.S_addr = INADDR_ANY;
    ::bind(s, (sockaddr*)&si, sizeof(si));
    
    // 加入多播组
    ip_mreq    mcast;
    mcast.imr_interface.S_un.S_addr = INADDR_ANY;
    mcast.imr_multiaddr.S_un.S_addr = ::inet_addr("192.168.0.1");  // 多播地址为234.5.6.7
    ::setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast));


    // 接收多播组数据
    printf(" 开始接收多播组上的数据... \n");
    char buf[1280];
    int nAddrLen = sizeof(si);
    while(TRUE)
    {
        int nRet = ::recvfrom(s, buf, strlen(buf), 0, (sockaddr*)&si, &nAddrLen);
        if(nRet != SOCKET_ERROR)
        {
            buf[nRet] = '\0';
            printf(buf);
        }
        else
        {
            int n = ::WSAGetLastError();
            break;
        }
    }
}

运行结果:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端之路

chrome 插件实现mac地址获取

浏览器无法通过js获取到硬件信息众所周知,ie是也是通过ActiveX来完成的。 由于我们一直使用Chrome,因此考虑开发chrome插件。 普通chrome...

3.7K10
来自专栏佳爷的后花媛

gitbookGitBook Toolchain Documentation

This document aims to be a comprehensive guide to GitBook. It contains the full ...

1022
来自专栏数据库新发现

VCS学习笔记

VERITAS Cluster Server(VCS) connects, or clusters, multiple, independent systems...

1032
来自专栏Netkiller

怎样制作RPM包

怎样制作RPM包 摘要 我在网上找RPM包的制作例子几乎都是C源码编译安装然后生成RPM包, 而我的程序不是C写的很多时候是脚本语言如Python, PHP 甚...

6376
来自专栏三杯水

DNS主从服务器搭建

http://blog.51cto.com/yichenyang/1911098 http://blog.51cto.com/wubinary/1379595

1802
来自专栏bboysoul

linux编译安装apache

wget http://mirrors.ustc.edu.cn/apache/httpd/httpd-2.4.25.tar.gz tar -zxvf http...

2033
来自专栏数据库新发现

Oracle诊断案例-Spfile案例一则

情况说明: 系统:SUN Solaris8 数据库版本:9203 问题描述:工程人员报告,数据库在重新启动时无法正常启动.检查发现UNDO表空间丢失. 问题诊断...

913
来自专栏潇涧技术专栏

Gradle Plugin for Android Development User Guide 2

Gradle Plugin for Android Development User Guide (2)

911
来自专栏刘君君

一个feign使用不当的问题

以上配置在不熟悉feign-hystrix 或者查看 Feign Hystrix Fallbacks 的可能感觉并没有问题,项目启动也是正常

1443
来自专栏乐沙弥的世界

Failed to upgrade Oracle Cluster Registry configuration(root.sh)

    最近在给客户基于Suse 11 sp3安装Oracle 10g RAC,在安装完clusterware执行/u01/app/crs/root.sh时收...

851

扫码关注云+社区

领取腾讯云代金券