一、Windows上的组播通信
基本和linux上的socket编程一致,稍微有点区别
以下是我测验可以使用的代码,
客户端
// 广播处理回复消息回调
typedef void(*handMulticastRsp)(char* rspstr, int len);
// 发送组播消息
// buff 发送内容
// len 发送内容长度
// groupIp 组播地址
// port 端口
// callbk 回调函数处理回复消息
// ms 等待回复超时时间
int multicast_sendmsg_wait(char* buff, int len, char* groupIp, int port, handMulticastRsp callbk, unsigned int ms) {
SOCKET socketfd = 0;
int ret = 0;
int selret = 0;
if (NULL==buff || len<=0 || NULL==groupIp)
return -TCPIPERR_CHECK_PARAM;
// 检查IP的合法性
#if __WIN32
WORD sockVersion=MAKEWORD(2,2);
WSADATA wsaData;//WSADATA结构体变量的地址值
if(WSAStartup(sockVersion, &wsaData)!=0)
{
printf("WSAStartup() error!");
return 0;
}
#endif
// 创建套接字
//socketfd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK, 0);
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET==socketfd) {
printf("创建套接字失败, errno %d\n", errno);
WSACleanup();
return -TCPIPERR_SOCKET_CREATE;
}
// 设置为非阻塞
// 设置同主机还是跨主机
//int iFlag = 1; // 0-同一台主机 1-夸主机
//ret = setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&iFlag, sizeof(iFlag));
// 设置发送地址,地址即是组播地址
struct sockaddr_in cliaddr;
memset(&cliaddr,0,sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(10000); // 接收端需要绑定9999端口
// 发送组播消息, 需要使用组播地址, 和设置组播属性使用的组播地址一致就可以
inet_pton(AF_INET, groupIp, &cliaddr.sin_addr.s_addr);
// 数据广播
ret = sendto(socketfd, buff, len, 0, (struct sockaddr*)(&cliaddr), sizeof(struct sockaddr));
if (ret<=0) {
printf("发送组播失败, errno %d\n", errno);
ret = -TCPIPERR_SENDMSG;
}
#if 0
#if 0
if (ms>0) {
// 指定了等待时间,等待回复消息,这里如果不需要知道发送端地址,都指定为空
ret = recvfrom(socketfd, buff, len, 0, NULL, NULL);
if (-1==ret) {
printf("接收消息失败, errno %d\n", errno);
ret = -TCPIPERR_RECVMSG;
}
}
#else
while ((ret=recvfrom(socketfd, buff, len, 0, NULL, NULL))>0)
{
printf("获取消息 %s, ret %d\n", buff, ret);
}
printf("<== ret %d\n", ret);
#endif
#endif
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(socketfd, &rfds);
// 设置超时时间
tv.tv_sec = 0;
tv.tv_usec = 10000;
// 预计读取数据为超时
ret = -TCPIPERR_WAITRECV_TIMEOUT;
start_select:
selret = select(socketfd+1, &rfds, NULL, NULL, &tv);
if (-1==selret) {
ret = -TCPIPERR_SELECT;
} else if (0 == selret) {
printf("等待数据超时\n");
//ret = -TCPIPERR_WAITRECV_TIMEOUT;
} else {
// >0,有数据
ret = recvfrom(socketfd, buff, len, 0, NULL, NULL);
if (-1==ret) {
ret = -TCPIPERR_RECVMSG;
goto error_set;
}
// printf("获取消息 %s, ret %d\n", buff, ret);
if (ret>0 && NULL!=callbk) {
callbk(buff, ret);
}
// 标记读取成功,
ret = 0;
// 重新监听是否有数据返回
goto start_select;
}
error_set:
closesocket(socketfd);
WSACleanup();
return ret;
}
二、遇到的问题
1、发送组播消息,另一台设备监听组播消息,然而,收不到消息
结论:虚拟网卡导致的组播监听异常,监听到虚拟网卡上了
# cmd 查询加入网络情况
netsh interface ipv4 show joins
随后我吧其他虚拟网卡禁用,开发板就能正常收到组播数据了。
感谢@dreamwatchman提供的解决思路
Linux、windows组播通信所遇坑集合
推荐一个好用的工具
socket调试工具