多播_1

IPPROTO_IP
1.IP_HDRINCL,布尔型,仅适用于原始套接字(SOCK_RAW)
如果应用程序希望接收IP层及IP层以上的所有数据或者自行组装包含IP层在内的报文,那么可以设置该选项为TRUE。
2.IP_ADD_MEMBERSHIP,struct ip_mreq结构,用于加入多播组
该选项用于将指定网络接口上的套接字加入IP多播组,此套接字必须是AF_INET地址族并且类型为SOCK_DGRAM。
struct ip_mreg{ 
  struct in_addr imr_multiaddr;/*IP multicast address of group*/ 
  struct in_addr imr_interface;/*local IP address of interface*/ 
}; 
其中imr_multiaddr对应于打算加入的多播组IPv4地址;而imr_interface是本地接口的IP地址,也可以设置为INADDR_ANY,表明选择的是默认接口。
3.IP_DROP_MEMBERSHIP,struct ip_mreq结构,由于退出多播组,该选项的使用与IP_ADD_MEMBERSHIP类似。
4.IP_MULTICAST_IF,BOTH,DWORD类型,设置/读取多播的本地接口。
IP_MULTICAST_IF选项用于设置或读取本地接口,在设置了本地的多播外出接口后,本地机器以后发出的任何多播数据都会经由它传送出去,该选项多用于多穴主机。
5.IP_MULTICAST_LOOP,BOTH,布尔类型,用于启用或禁止多播报文回环。
在默认情况下,当发送IP多播数据时,如果发生套接字本身也属于该多播组,那么数据会原封不动的返回一份至套接字---回环(loopback)。若将该选项设为FALSE,发出的任何数据对都不会投递至套接字的进入数据队列中。
6.IP_MULTICAST_TTL,BOTH,DWORD类型,设置/读取套接字上IP多播的TTL值。
在默认情况下,多播数据报采用的TTL值为1,IP_MULTICAST_TTL选项可用于读取或设置该值。多播TTL值的大小影响到多播数据的传播范围。只有在有效范围内的组成员才会收到数据。


设计报文广播的最初目的是用于资源发送和减少数据交互量。但事实上,由于报文广播时,同一网段内的所有主机,无论有没有参与广播应用,都必须完成对数据报的处理。被广播的UDP报文会被接收主机的系统协议栈逐层处理,知道传输层将其交付监听相应端口的应用进程或者丢弃。因此,频繁的大数据量的报文广播会严重影响网络上其他主机的正常运行。而多播方式在具有广播的优点同时,很好的解决了这个问题。
 
一个简单的多播库:
//*************MCastLib.h***************// 
#ifndef _MCASTLIB_H_ 
#define _MCASTLIB_H_ 
 
#include<winsock2.h> 
#include<ws2tcpip.h> 
 
#ifdef __cplusplus 
extern "C" { 
#endif 
 
int mc_join(SOCKET s,struct in_addr *mcaddr,struct in_addr *local_if); 
int mc_setIF(SOCKET s,const DWORD local_out_if); 
int mc_getIF(SOCKET s,DWORD *local_out_if); 
int mc_setTTL(SOCKET s,const DWORD ttl); 
int mc_getTTL(SOCKET s,DWORD *ttl); 
int mc_setLoop(SOCKET s,const BOOL flag); 
int mc_getLoop(SOCKET s,BOOL *flag); 
int mc_leave(SOCKET s,struct in_addr *mcaddr,struct in_addr *local_if); 
 
#ifdef __cplusplus 
} 
#endif 
#endif 
 
//************************MCastLib.cpp*****************// 
#include "MCastLib.h" 
//本地接口local_if加入多播组mcaddr 
int mc_join(SOCKET s,struct in_addr *mcaddr,struct in_addr *local_if) 
{ 
    struct ip_mreq mreq; 
    memcpy(&(mreq.imr_interface),local_if,sizeof(struct in_addr)); 
    memcpy(&(mreq.imr_multiaddr),mcaddr,sizeof(struct in_addr)); 
    return (setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mreq,sizeof(mreq))); 
} 
//为多播报文设置外出接口 
int mc_setIF(SOCKET s,const DWORD local_out_if) 
{ 
    return (setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,(char*)&local_out_if,sizeof(local_out_if))); 
} 
//获取多播报文的外出接口 
int mc_getIF(SOCKET s,DWORD *local_out_if) 
{ 
    int len = sizeof(DWORD); 
    return (getsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,(char*)local_out_if,&len)); 
} 
//设置外出多播报文的ttl值,默认为1 
int mc_setTTL(SOCKET s,const DWORD ttl) 
{ 
    return (setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&ttl,sizeof(ttl))); 
} 
//获取外出多播报文的ttl值 
int mc_getTTL(SOCKET s,DWORD *ttl) 
{ 
    int len = sizeof(DWORD); 
    return (getsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,(char*)ttl,&len)); 
} 
//启用或禁止多播报文回环 
int mc_setLoop(SOCKET s,const BOOL flag) 
{ 
    return (setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)&flag,sizeof(flag))); 
} 
//获取本地多播回环状态 
int mc_getLoop(SOCKET s,BOOL *flag) 
{ 
    int len = sizeof(BOOL); 
    return (getsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)flag,&len)); 
} 
//本地接口local_if离开多播组mcaddr 
int mc_leave(SOCKET s,struct in_addr *mcaddr,struct in_addr *local_if) 
{ 
    struct ip_mreq mreq; 
    memcpy(&(mreq.imr_interface),local_if,sizeof(struct in_addr)); 
    memcpy(&(mreq.imr_multiaddr),mcaddr,sizeof(struct in_addr)); 
    return (setsockopt(s,IPPROTO_IP,IP_DROP_MEMBERSHIP,(char*)&mreq,sizeof(mreq))); 
} 
 
接收多播数据
SOCKADDR_IN local; 
memset(&local,0,sizeof(SOCKADDR_IN)); 
local.sin_family=AF_INET; 
local.sin_port=htons(5050); 
local.sin_addr.s_addr=inet_addr("202.119.9.199"); 
bind(sock,(SOCKADDR*)&local,sizeof(SOCKADDR_IN)); 
struct in_addr mcaddr; 
//202.119.9.199加入多播组226.1.2.3 
mcaddr.s_addr=inet_addr("226.1.2.3"); 
mc_join(sock,&mcaddr,&(local.sin_addr)); 
 
//接收数据 
char buf[65]; 
while(TRUE) 
{ 
    memset(buf,0,65); 
    recvfrom(sock,buf,65,0,NULL,NULL); 
} 
上述代码使套接字加入多播组226.1.2.3,并接受发往该组的数据。当调用mc_join函数时,内核会自动向该组发送一个“IGMP v2 Memebership Report”报文,该报文会被组内的所有主机及路由器接收。
在套接字关闭时,无论有没有显示的调用mc_leave函数,进程都会离开多播组。
 
发送多播数据
SOCKET sock = socket(AF_INET,SOCK_DGRAM,0); 
//获取默认的多播报文TTL值和回环状态 
DWORD ttl; 
BOOL loop; 
mc_getTTL(sock,&ttl); 
mc_getLoop(sock,&loop); 
printf("Multicast default: TTL=%d, LoopBack=%d
",ttl,loop); 
//设置多播TTL值为219 
ttl=219; 
mc_setTTL(sock,ttl); 
//想多播组发送数据 
SOCKADDR_IN to; 
memset(&to,0,sizeof(SOCKADDR_IN)); 
to.sin_family=AF_INET; 
to.sin_port=htons(9999); 
to.sin_addr.s_addr=inet_addr("226.1.2.3"); 
char *buf="hello!"; 
int res = sendto(sock,buf,6,0,(SOCKADDR*)&to,sizeof(to)); 


 
原文地址:https://www.cnblogs.com/profession/p/4464436.html