(有谁能告诉我怎么把上面的表格去掉,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.0~247.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 抓包情况:
// TODO
本文介绍了一种基于C语言实现的IP多播通信方法,详细展示了如何设置套接字选项来加入和离开多播组,并提供了完整的多播发送和接收代码示例。
1649

被折叠的 条评论
为什么被折叠?



