IP多播

                      1   多播地址                    windows

IP多播地址採用D類IP地址肯定多播的組,地址範圍是224.0.0.0239.255.255.255.socket

                       2 組管理協議(IGMP)              tcp

兩個多播節點之間的全部路由器必須支持IGMP協議this

任何沒有開啓IGMP的路由器僅簡單的丟棄接收到的多播數據spa

                      3   使用IP多播                        code

      1     加入離開組      blog

     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

 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; } } }

運行結果:

相關文章
相關標籤/搜索