博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IP多播
阅读量:6271 次
发布时间:2019-06-22

本文共 4900 字,大约阅读时间需要 16 分钟。

                      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 
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 
#include
#include
// 初始化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; } }}

运行结果:

转载地址:http://ioopa.baihongyu.com/

你可能感兴趣的文章
关于结构体占用空间大小总结(#pragma pack的使用)
查看>>
通过浏览器查看nginx服务器状态配置方法
查看>>
shell简介
查看>>
android 使用WebView 支持播放优酷视频,土豆视频
查看>>
怎么用secureCRT连接Linux
查看>>
C# 使用WinRar命令压缩和解压缩
查看>>
linux学习笔记一----------文件相关操作
查看>>
Mono for Android 优势与劣势
查看>>
服务器端开发技术
查看>>
Python3中urllib详细使用方法(header,代理,超时,认证,异常处理)
查看>>
ajax提交多个对象,使用序列化表单和FormData
查看>>
深入分析由前序和中序重构二叉树问题
查看>>
leetcode 题解 || Valid Parentheses 问题
查看>>
将图片转成base64字符串并在JSP页面显示的Java代码
查看>>
什么是WeakHashMap--转
查看>>
js 面试题
查看>>
第二十二节,三元运算
查看>>
Yacc 与 Lex 快速入门
查看>>
Unity中HDR外发光的使用
查看>>
Flume负载均衡配置
查看>>