组播通过测试,双网卡或多网卡设置在不同IP段。
IP地址空间被划分为A、B、C三类。第四类即D类地址被保留用做组播地址。在第四版的IP协议(IPv4)中,从224.0.0.0到239.255.255.255间的所有IP地址都属于D类地址。所以要利用组播发送数据必须有一个虚拟的组播IP,所谓虚拟,就是你不必把网卡地址设为此IP,而只需在你程序中出现,相当于建立一个以此IP为标志的集合,所有想加入组播的必须加入这个集合之中,发送组播时,往此IP发送,所有此集合中的主机均可接收到相同的数据,其处理转发过程由上一级路由器或者集线器处理。一台主机可以加入到多个组播组之中,一个组播组可以含有多台主机,但是这些主机必须在同一IP段,即在同一个路由之下。
下面一个程序可以实现UDP组播的发送与接收。只能发送或者只能接收,如果都想,自己建个进程或线程吧,把程序放进去就行。
//头文件
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
//全局变量定义
char host_name[] = "239.5.5.5"; //组播IP地址
char local_IP[] = "192.168.2.10"; //本机IP地址
char mess_send[]="hello"; //待发数据
//char mess_rec[1024]; //接收缓冲
int port = 5115; //端口号
//主程序
int main()
{
struct ip_mreq command;
int loop = 1;
int i = 0;
/* 多播循环 */
int iter = 0;
int sin_len;
int sFd1;
struct sockaddr_in sin,address; //本机、目标机socket参数
/****************发送目标机Socket赋值*********************/
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(host_name);
address.sin_port = htons(port);
/***************本机Socket赋值***********************/
if((sFd1 = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("***********************socket1*****************\n");
exit(-1);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);
if(bind(sFd1,(struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("***********************bind1********************\n");
exit(-1);
}
/*将本地IP绑定到相应组播上,经过测试,如果只有一块网卡,或者有多快网卡,只是用第一块(默认的)可以不设置,但是如果有多块网卡,或者使用多块网卡中的非默认的,必须绑定*/
loop = 1;
unsigned long seladdr;
seladdr = inet_addr(local_IP);
if(setsockopt(sFd1,IPPROTO_IP, IP_MULTICAST_IF,(char *)&seladdr, sizeof(seladdr)) < 0)
{
perror("setsockopt:IP_MULTICAST_LOOP");
exit(-1);
}
/* 加入一个组播组,支持组播,进一步告诉Linux内核,特定的套接口即接受广播数据*/
command.imr_multiaddr.s_addr = inet_addr(host_name);
//command.imr_interface.s_addr = htonl(INADDR_ANY);
command.imr_interface.s_addr = inet_addr(local_IP);
if(command.imr_multiaddr.s_addr == -1)
{
perror("224.0.0.1 not a legal multicast address");
exit(-1);
}
if (setsockopt(sFd1, IPPROTO_IP, IP_ADD_MEMBERSHIP,&command, sizeof(command)) < 0)
{
perror("setsockopt:IP_ADD_MEMBERSHIP\n");
}
//以下接收数据
/*while(i++ < 50)
{
sin_len = sizeof(sin);
// memset(&message, 0, sizeof(message));
if(recvfrom(sFd1, message, 256, 0, (struct sockaddr *)&sin, &sin_len) == -1)
{
perror("***********************recvfrom********************\n");
}
printf("receive: %s\n",message);
}
*/
//以下发送数据
while(i< 200)
{
i++;
printf("%d\n",i);
sleep(1);
if(sendto(sFd1, message, sizeof(message), 0,(struct sockaddr *)&address, sizeof(address)) < 0)
{
perror("************************sendto****************************\n");
exit(-1);
}
}
//结束
close(sFd1);
return 0;
}