zoukankan      html  css  js  c++  java
  • IP多播

                          1   多播地址                    

    IP多播地址采用D类IP地址确定多播的组,地址范围是224.0.0.0239.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;
            }
        }
    }

    运行结果:

  • 相关阅读:
    安装mysql_cluster报错: Data::Dumper丢失
    win10 nodejs指定ionic版本安装(npm方式)
    java项目报错: org.springframework.beans.factory.BeanCreationException找不到mapper.xml文件
    java项目跑起来报错: 程序报 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". 错误
    ~/.bashrc文件写错, 导致Linux全部命令丢失
    tomcat热启动没问题, 访问项目报500解决办法
    安装OpenOffice
    redhat6.4 elasticsearch1.7.3安装配置
    MySQL新建用户保存的时报错:The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement
    zabbix zabbix_agentd.conf详解
  • 原文地址:https://www.cnblogs.com/xing901022/p/2731702.html
Copyright © 2011-2022 走看看