MULTICAST && BROADCAST


       

(有谁能告诉我怎么把上面的表格去掉,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 address
	struct in_addr imr_address;   // IP address of local interface
	int            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";
#endif

	struct 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 1
	pLocalInAddr->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;
	}
#endif
	
	printf("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 network
	if( 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]$ ./multicast
local address = 0.0.0.0

remote address = 172.16.0.248
================
by vicno at 2012-05-22
i386-Red Hat-gcc-4.1.2
http://blog.cdsn.net/xuyunzhang
copyright: All Reserved
================


remote address = 172.16.1.110
================
M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
Man: "ssdp:discover"
MX: 5
ST: urn:schemas-upnp-org:service:WANPPPConnection:1


================


remote address = 172.16.1.110
================
M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
Man: "ssdp:discover"
MX: 5
ST: urn:schemas-upnp-org:service:WANIPConnection:1



================

CTRL + C 结束循环:


remote address = 172.16.1.110
================
M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
Man: "ssdp:discover"
MX: 5
ST: upnp:rootdevice

g: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 抓包情况:MULTICAST && BROADCAST_第1张图片





// TODO

你可能感兴趣的:(MULTICAST && BROADCAST)