linux下可通过指定网卡名字来将网卡加入组播
一般来说网卡名为 eth0,eth1之类的,具体的需要通过ifconfig查看
具体逻辑就是通过指定的网卡名来获取网卡ip,后面就跟普通的创建udp套接字一样了,需要注意的是将网卡绑定到组播最好启用地址重用来避免端口相同导致的失败
SO_REUSEADDR可以用在以下四种情况下。 (摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。
需要注意的是,设置端口复用函数要在绑定之前调用,而且只要绑定到同一个端口的所有套接字都得设置复用
void InitSocket(int *UdpSocket, int iPort,char * ethName,char * MulticIp)
{
int on = 1;
//struct ip_mreq mreq; /*加入多播组*/
struct sockaddr_in servaddr;
struct ifreq ifr;
if ((*UdpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("creat UdpSocket socket failed!");
return ;
}
strcpy(ifr.ifr_name, ethName);
//SIOCGIFADDR标志代表获取接口地址
if (ioctl(*UdpSocket, SIOCGIFADDR, &ifr) < 0)
{
perror("ioctl");
close(*UdpSocket);
*UdpSocket = -1;
return ;
}
//printf("%s\n", inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(iPort);
servaddr.sin_addr = ((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr;
if((setsockopt(*UdpSocket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0)
{
perror("set UDP_sock sockopt failed");
close(*UdpSocket);
*UdpSocket = -1;
return ;
}
if (bind(*UdpSocket, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind UDP_sock sockopt failed");
close(*UdpSocket);
*UdpSocket = -1;
return ;
}
servaddr.sin_addr.s_addr = inet_addr ((char *)MulticIp);
servaddr.sin_port = htons ((unsigned short)iPort);
if ( connect(*UdpSocket, (struct sockaddr *)&servaddr,sizeof(servaddr)) == -1 )
{
perror("connect UDP_sock sockopt failed");
close(*UdpSocket);
*UdpSocket = -1;
return ;
}
}
上述代码先通过ioctl获取指定网卡名的ip地址,再绑定ip 最后连接
具体使用如下:
int MulticSocket = -1;
InitSocket(&MulticSocket, 12345, "eth0", "225.1.2.3");
send(MulticSocket ,bufData,bufferlen,0);
然后就可以在组播地址225.1.2.3端口号12345 接收报文了
以上