一台ANDROID4.0的真机,不是模拟器,建立接收组播数据用的套接字,bind,setsockopt等等在代码层面上一切正常,但一直没有发现机器发出IGMP包
近乎同样的代码,在LINUX台式机上跑着一切正常,也的确是发出了IGMP的加入组播组的数据包。有人说这个问题在于系统内核,但真机上是可以向组播组发包的,不知道这样是不是就可以判定内核是支持组播的。busybox ifconfig eth0的结果是"UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1",不知道这样是不是也可以判定内核支持组播。网上也有好多说法是对诸如对 ip_forward及icmp_echo_ignore_broadcasts的设置,本人不甚了解,乱试一通,无果。各位大侠倘若哪怕有些许想法,也请不吝赐教。源码奉上:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <map>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>#define GroupIP "224.7.7.7" //要加入的组播组
#define GroupPort 7777 //组播监听端口int main(void)
{
int s; //套接字
struct sockaddr_in srv; //组播地址
struct ip_mreq mreq; //这儿也用ip_mreqn测试过,没有新发现。 //建立套接字
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("socket failed");
return false;
} {//绑定IP
memset(&srv,0, sizeof(srv));
srv.sin_family = AF_INET;
srv.sin_port = htons(GroupPort);
if (inet_aton(GroupIP, &srv.sin_addr) < 0)
{
printf("inet_aton failed");
return false;
}
if (bind(s, (struct sockaddr *) &srv, sizeof(srv)) < 0)
{
close(s);
printf("bind failed");
return false;
}
} {//加入组播组
if (inet_aton(GroupIP, &mreq.imr_multiaddr) < 0)
{
close(s);
printf("inet_aton failed");
return false;
}
inet_aton("192.168.15.55", &mreq.imr_interface);//"192.168.15.55"是本机IP,如果指定INADDR_ANY需要配置路由。 unsigned char ttl=200;
setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); int errorSetSockOpt=setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
if ( errorSetSockOpt< 0)
{
close(s);
printf("join failed:%d:%d",errorSetSockOpt,errno);
return false;
}
} {//等待一段时间,传说立即退出的话,即便正常的系统也不会发出IGMP
sleep(1);
} {//退出组播组
if ((setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*) &mreq, sizeof(mreq))) < 0)
{
printf("drop failed:%d",errno);
close(s);
return false;
}else
{
printf("drop successed");
}
}
close(s);
return true;
}androidsocket组播 无法加入
近乎同样的代码,在LINUX台式机上跑着一切正常,也的确是发出了IGMP的加入组播组的数据包。有人说这个问题在于系统内核,但真机上是可以向组播组发包的,不知道这样是不是就可以判定内核是支持组播的。busybox ifconfig eth0的结果是"UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1",不知道这样是不是也可以判定内核支持组播。网上也有好多说法是对诸如对 ip_forward及icmp_echo_ignore_broadcasts的设置,本人不甚了解,乱试一通,无果。各位大侠倘若哪怕有些许想法,也请不吝赐教。源码奉上:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <map>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>#define GroupIP "224.7.7.7" //要加入的组播组
#define GroupPort 7777 //组播监听端口int main(void)
{
int s; //套接字
struct sockaddr_in srv; //组播地址
struct ip_mreq mreq; //这儿也用ip_mreqn测试过,没有新发现。 //建立套接字
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("socket failed");
return false;
} {//绑定IP
memset(&srv,0, sizeof(srv));
srv.sin_family = AF_INET;
srv.sin_port = htons(GroupPort);
if (inet_aton(GroupIP, &srv.sin_addr) < 0)
{
printf("inet_aton failed");
return false;
}
if (bind(s, (struct sockaddr *) &srv, sizeof(srv)) < 0)
{
close(s);
printf("bind failed");
return false;
}
} {//加入组播组
if (inet_aton(GroupIP, &mreq.imr_multiaddr) < 0)
{
close(s);
printf("inet_aton failed");
return false;
}
inet_aton("192.168.15.55", &mreq.imr_interface);//"192.168.15.55"是本机IP,如果指定INADDR_ANY需要配置路由。 unsigned char ttl=200;
setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); int errorSetSockOpt=setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
if ( errorSetSockOpt< 0)
{
close(s);
printf("join failed:%d:%d",errorSetSockOpt,errno);
return false;
}
} {//等待一段时间,传说立即退出的话,即便正常的系统也不会发出IGMP
sleep(1);
} {//退出组播组
if ((setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*) &mreq, sizeof(mreq))) < 0)
{
printf("drop failed:%d",errno);
close(s);
return false;
}else
{
printf("drop successed");
}
}
close(s);
return true;
}androidsocket组播 无法加入
if CONFIG_IP_MULTICAST disabled,setsockopt will succeed,but none igmp will be sent.
however,i have to send igmp manually...........
what a broken heart........references:
http://code.google.com/p/android/issues/detail?id=2917
https://groups.google.com/forum/?fromgroups#!topic/android-developers/BTwBRDvHBds
http://stackoverflow.com/questions/3179710/how-to-receive-multicast-packets-on-android
http://www.programmingmobile.com/2012/01/multicast-and-android-big-headache.html
https://sites.google.com/site/miclinuxcorner/technology/multicast-routing
http://unix.stackexchange.com/questions/25872/how-can-i-know-if-ip-multicast-is-enabled
http://cafbit.com/entry/testing_multicast_support_on_android
http://code.google.com/p/android/issues/detail?id=51195
**文件:client.c
**编写者:feixiao
**编写日期:2013年3月27日
**简要描述:多播客户端
**修改日期:
**注:加入多播组,用于接收服务器发送的信息
**************************************************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>#define BUFFER_SIZE 1024 // 每次传送的buffer大小
/***** 主函数 *************************************************************************************************/
int main(void)
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
char bReuse = 1;
struct sockaddr_in si;
struct ip_mreq mcast;
FILE* pFile = NULL;
char* pFilePath = "./test.mp4";
char buffer[BUFFER_SIZE] ={'\0'};
int flag = 0; int nAddrLen = sizeof(si);
int count = 0;
int i = 0;
struct ip_mreq_source mreqsrc;
// 允许其他进程使用绑定的地址
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(bReuse));
// 绑定到6666 端口
si.sin_family = AF_INET;
si.sin_port = htons(6666);
si.sin_addr.s_addr = INADDR_ANY;
bind(sock, (struct sockaddr*)&si, sizeof(si));
// 加入多播组
mcast.imr_interface.s_addr = INADDR_ANY;
mcast.imr_multiaddr.s_addr = inet_addr("172.17.191.255"); // 多播地址为234.5.6.7
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast));
// 设置带源的多播地址
// 设置ip_mreq_source 结构
mreqsrc.imr_interface.s_addr = inet_addr("172.17.165.102");
mreqsrc.imr_multiaddr.s_addr = inet_addr("234.5.6.7");
// 添加源地址172.17.186.150
mreqsrc.imr_sourceaddr.s_addr = inet_addr("172.17.186.150");
setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqsrc, sizeof(mreqsrc));
// 添加源地址172.17.187.3
mreqsrc.imr_sourceaddr.s_addr = inet_addr("172.17.187.3");
setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqsrc, sizeof(mreqsrc));
// 添加源地址172.17.187.3
mreqsrc.imr_sourceaddr.s_addr = inet_addr("172.17.186.216");
setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqsrc, sizeof(mreqsrc));
// 接收多播组数据
printf(" 开始接收多播组234.5.6.7 上的数据... \n");
// 文件数据准备
pFile = fopen(pFilePath,"wb+");
if (NULL == pFile)
{
printf("文件打开失败");
}
while(1)
{
int nRet = recvfrom(sock, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&si, &nAddrLen);
if(nRet != -1)
{
//cout<<buffer<<endl;
fwrite(buffer,1,BUFFER_SIZE,pFile);
printf("客户端接收 %d KB\n",++i);
bzero(buffer,BUFFER_SIZE);
}
else
{
break;
}
}
fclose(pFile);
close(sock);
return 0;
}
更换了内核,就OK了。to:naruto12345
我现在还没有进入接收组播的环节,被别的事给耽误了。
丢包严重的话,可以抓抓包试试,看看在哪儿丢的,然后再解决。