MULTICAST && BROADCAST

来源:互联网 发布:美萍软件下载 编辑:程序博客网 时间:2024/06/06 08:52


    

(有谁能告诉我怎么把上面的表格去掉,cdsn 的blog 编辑很不友好,还Chinese software develop net 我呸!)

IP地址的划分:


A类地址:10.0.0.0~10.255.255.255
B类地址:172.16.0.0~172.31.255.255
C类地址:192.168.0.0~192.168.255.255

D类地址:224.0.0.0~239.255.255.255

E类地址:240.0.0.0247.255.255.255 (试验用)

广播地址:255.255.255.255


保留地址
10.x.x.x ; 172.16.x.x ~ 172.31.x.x ; 192.168.x.x ;用于私有地址(private address),以避免以后接入公网(public address)时引起地址混乱。要使用NAT技术接入公网。127.0.0.1 用于测试的loopback,特指本机地址224.0.0.1 特指所有主机(包括路由器);224.0.0.2 特指所有路由器255.255.255.255 广播受限地址,路由器不转发宿地址为该地址的包0.0.0.0 表示可以匹配任何地址

Multicast 多播

发送多播包 没必要加入相应的多播组,无需特殊处理即可向相应的D类多播地址发送多播数据;

接收多播包 需要加入明确的多播地址:
setsockopt(udp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,  &mcreq, sizeof(struct ip_mreq) )
并且指定相应的接收网口:
setsockopt(udp_fd, IPPROTO_IP, IP_MULTICAST_IF, pLocalInAddr, sizeof(struct sockaddr_in) )
离开多播组:

setsockopt(udp_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcreq, sizeof(struct ip_mreq) )

多播发送 和 多播接收 代码:

#include <stdio.h>#include <string.h>#include <stdlib.h>// for exit#include <arpa/inet.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/ip.h>#include <net/if.h>// for ifreq#include <sys/ioctl.h>// for ioctl#include <signal.h>// for signal#include <sys/time.h>// for select#include <unistd.h>#define MCAST_ADDR "239.255.255.250"#define PORT 1900#define TRUE 1#define FALSE 0#define USE_IP_MREQ/*#include <net/if.h>struct ifreq {char ifr_name[IFNAMSIZ];union{struct sockaddr ifru_addr;struct sockaddr ifru_dstaddr;struct sockaddr ifru_broadaddr;short ifru_flags;int ifru_metric;caddr_t ifru_data;} ifr_ifru;};#define ifr_addr ifr_ifru.ifru_addr#define ifr_dstaddr ifr_ifru.ifru_dstaddr#define ifr_broadaddr ifr_ifru.ifru_broadaddr#include <netinet/ip.h>struct ip_mreq{        struct in_addr imr_multiaddr; // IP multicast group address        struct in_addr imr_interface; // IP address of local interface};struct ip_mreqn {struct in_addr imr_multiaddr; // IP multicast group addressstruct in_addr imr_address;   // IP address of local interfaceint            imr_ifindex;   // interface index};*/unsigned long getInetAddr(const char *intfName );void interruptHandler(int signal);int keepLoop = 1;int main(int argc, char *argv[]){int udp_fd = -1;int opt = 1, onflag = 1;socklen_t remoteAddrLen = 0;char buf[1024] = #if 1"by vicno at 2012-05-22\n\i386-Red Hat-gcc-4.1.2\n\http://blog.cdsn.net/xuyunzhang\n\copyright: All Reserved";#else"M-SEARCH * HTTP/1.1\n\Host:239.255.255.250:1900\n\ST:urn:schemas-upnp-org:device:WANPPPConnection:1\n\Man:\"ssdp:discover\"\n\MX:3";#endifstruct sockaddr_storage localAddr;struct sockaddr_storage remoteAddr;struct sockaddr_in *pLocalInAddr = NULL;struct sockaddr_in *pRemoteInAddr = NULL;struct ip_mreq mcreq;struct timeval timeout;fd_set readfds;int nfds;signal(SIGINT, interruptHandler);signal(SIGTERM, interruptHandler);if( (udp_fd = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP)) == -1 ){perror("socket");return 0;}if (setsockopt(udp_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0){perror("setsockopt");close(udp_fd);return 0;}/*// enabled to send data to broadcast address.if ( setsockopt(udp_fd, SOL_SOCKET, SO_BROADCAST, &onflag, sizeof(onflag)) < 0){perror("setsockopt");close(udp_fd);return 0;}*/memset(&localAddr, 0, sizeof(struct sockaddr_storage));pLocalInAddr = (struct sockaddr_in *)&localAddr;pLocalInAddr->sin_family = AF_INET;pLocalInAddr->sin_port = htons(PORT);#if 1pLocalInAddr->sin_addr.s_addr = htonl(INADDR_ANY);// pLocalInAddr->sin_addr.s_addr = getInetAddr("eth0");#else// it will not enable to receive any multicast packets,// if assign the address with the specific value instead of htonl(INADDR_ANY),// that's really confused me .if( inet_aton( "172.16.0.248", &(pLocalInAddr->sin_addr) ) == 0 ){perror("inet_aton(): ");close(udp_fd);return 0;}#endifprintf("local address = %s\n\n", inet_ntoa( pLocalInAddr->sin_addr) );//Join multicast, enabled to recv data from multicast address.do{memset( &mcreq, 0, sizeof(struct ip_mreq) );inet_aton( MCAST_ADDR, &(mcreq.imr_multiaddr) );mcreq.imr_interface.s_addr = pLocalInAddr->sin_addr.s_addr;if( setsockopt(udp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcreq, sizeof(struct ip_mreq)) == -1 ){perror("setsockopt( IPPROTO_IP, IP_ADD_MEMBERSHIP ): ");break;}// restrict multicast messages sent on this socket to only go out this // interface and no other (doesn't say anything about multicast receives.)if( setsockopt(udp_fd, IPPROTO_IP, IP_MULTICAST_IF, pLocalInAddr, sizeof(struct sockaddr_in) ) == -1 ){perror("setsockopt( IPPROTO_IP, IP_MULTICAST_IF ): ");    break;}}while(0);// bind socket to a local address and port,which used to recv data from networkif( bind(udp_fd, (struct sockaddr *)&localAddr,sizeof(struct sockaddr_in)) != 0){perror("bind");close(udp_fd);return 0;}memset(&remoteAddr, 0, sizeof(struct sockaddr_storage));pRemoteInAddr = (struct sockaddr_in *)&remoteAddr;pRemoteInAddr->sin_family = AF_INET;pRemoteInAddr->sin_port = htons(PORT);// inet_aton() returns non-zero if the address is valid, zero if not.if( inet_aton( MCAST_ADDR, &(pRemoteInAddr->sin_addr) ) == 0 ){perror("inet_aton");close(udp_fd);return 0;}if( sendto(udp_fd, buf, strlen(buf), 0, (const struct sockaddr *)&remoteAddr, sizeof(struct sockaddr_in)) == -1){perror("sendto("MCAST_ADDR"): ");}nfds = udp_fd + 1;FD_ZERO(&readfds);FD_SET(udp_fd, &readfds);timeout.tv_sec = 60;timeout.tv_usec = 0;remoteAddrLen = sizeof(struct sockaddr_in);while(keepLoop){if( select( nfds, &readfds, NULL, NULL, &timeout) == -1 ){perror("select(): ");}if( FD_ISSET( udp_fd, &readfds ) ){memset(&remoteAddr, 0, sizeof(struct sockaddr_storage));if( recvfrom( udp_fd, buf, sizeof(buf), 0,(struct sockaddr *)pRemoteInAddr, &remoteAddrLen ) == -1 ){perror("recvfrom("MCAST_ADDR"): ");}printf("remote address = %s\n", inet_ntoa( pRemoteInAddr->sin_addr) );printf("================\n%s\n================\n", buf );printf("\n\n");}if( keepLoop == 0 )break;}if( setsockopt(udp_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcreq, sizeof(struct ip_mreq) ) == -1){perror("setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP): ");}close(udp_fd);printf("select timeout, exit now !!!\n");}void interruptHandler(int signal){keepLoop = 0;printf("interrupted, exit now !!!\n");exit(0);}unsigned long getInetAddr(const char *intfName ){struct ifreq ifreq;int udp_fd = -1;if( (udp_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1 ){perror("socket");return 0;}memset(&ifreq, 0, sizeof(ifreq));strcpy(ifreq.ifr_name, intfName);if( ioctl(udp_fd, SIOCGIFADDR, &ifreq) == -1 ){perror("ioctl(SIOCGIGADDR): "); close(udp_fd);return 0;}close(udp_fd);return ((struct sockaddr_in *)&(ifreq.ifr_addr))->sin_addr.s_addr;}


运行 ,以下是

[vinco@IPPBX-Server socket]$ [vinco@IPPBX-Server socket]$ ./multicastlocal address = 0.0.0.0remote address = 172.16.0.248================by vicno at 2012-05-22i386-Red Hat-gcc-4.1.2http://blog.cdsn.net/xuyunzhangcopyright: All Reserved================remote address = 172.16.1.110================M-SEARCH * HTTP/1.1Host: 239.255.255.250:1900Man: "ssdp:discover"MX: 5ST: urn:schemas-upnp-org:service:WANPPPConnection:1================remote address = 172.16.1.110================M-SEARCH * HTTP/1.1Host: 239.255.255.250:1900Man: "ssdp:discover"MX: 5ST: urn:schemas-upnp-org:service:WANIPConnection:1================

CTRL + C 结束循环:


remote address = 172.16.1.110================M-SEARCH * HTTP/1.1Host: 239.255.255.250:1900Man: "ssdp:discover"MX: 5ST: upnp:rootdeviceg:device:InternetGatewayDevice:1================interrupted, exit now !!![vinco@IPPBX-Server socket]$ [vinco@IPPBX-Server socket]$ 


发现可以收到自己(172.16.0.248)发送的多播包,和 172.16.1.110 发送的 标准 upnp discover包,
两者都是绑定在1900 端口并且加入多播地址239.255.255.250的网口。


wirshark 抓包情况:





// TODO