组播
组播通过测试,双网卡或多网卡设置在不同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 <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
char group_ip[] = "226.0.0.1"; //组播IP地址
char local_IP[] = "192.168.6.208"; //本机IP地址
int local_port = 26001; //端口号
/*
*group_ip 组播地址
*local_ip 本机的实际地址
*port 组播端口号
*/
int Init_Socket(char *group_ip, char *local_ip, short port)
{
int sockfd;
unsigned long seladdr;
int addr_len;
struct ip_mreq group_mreq;
struct sockaddr_in group_addr;
struct sockaddr_in local_addr;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("***********************socket error *****************\n");
return 0;
}
addr_len = sizeof (struct sockaddr_in);
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(port);
if(bind(sockfd,(struct sockaddr *)&local_addr, addr_len) < 0)
{
printf("***********************bind error ********************\n");
return 0;
}
/*将本地IP绑定到相应组播上,经过测试,如果只有一块网卡,或者有多快网卡,只是用第一块(默认的)可以不设置,但是如果有多块网卡,或者使用多块网卡中的非默认的,必须绑定*/
seladdr = inet_addr(local_ip);
if(setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF,(char *)&seladdr, sizeof(seladdr)) < 0)
{
printf("***********************setsockopt:IP_MULTICAST_LOOP***********************\n");
return 0;
}
/* 加入一个组播组,支持组播,进一步告诉Linux内核,特定的套接口即接受广播数据*/
group_mreq.imr_multiaddr.s_addr = inet_addr(group_ip);
group_mreq.imr_interface.s_addr = inet_addr(local_ip);
if(group_mreq.imr_multiaddr.s_addr == -1)
{
perror("224.0.0.1 not a legal multicast address");
return 0;
}
if(setsockopt(sockfd , IPPROTO_IP, IP_ADD_MEMBERSHIP,&group_mreq, sizeof(group_mreq)) < 0)
{
perror("setsockopt:IP_ADD_MEMBERSHIP\n");
return 0;
}
return sockfd;
}
int wait_for_read(int socket, int seconds)
{
int flag;
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(socket, &fds);
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
flag = select(socket + 1, &fds, NULL, NULL, &timeout);
if (flag > 0 && FD_ISSET(socket, &fds))
{
return 1;
}
printf("flag = %d status = %d \n", flag, FD_ISSET(socket, &fds));
return 0;
}
int main()
{
int ret;
int sFd1;
sFd1 = Init_Socket(group_ip, local_ip, port);
/* 循环接受用户输入的消息发送组播消息 */
while(1)
{
if (wait_for_read(sFd1, 2) == 1)
{
//recv msg
}
}
//结束
close(sFd1);
return 0;
}