编译环境为:VS2017
编译版本为:debug
编译结果为:X64和X86
测试结果:X86接收组播正常,X64接收报文不正常
代码如下:
-
初始化组播socket:
int ret;
udpsockfd[Task[TaskId]->TaskUdpNo].sockfd = ::socket(AF_INET,SOCK_DGRAM,0); //创建socket
if(INVALID_SOCKET == udpsockfd[Task[TaskId]->TaskUdpNo].sockfd)
{
Sleep(500);
continue;
}//1.设置允许其它进程使用绑定的地址 BOOL bReuse=TRUE; ret = ::setsockopt(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd,SOL_SOCKET,SO_REUSEADDR,(char*)&bReuse,sizeof(BOOL)); if(ret == SOCKET_ERROR) { ::shutdown(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, 2); ::closesocket(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd); udpsockfd[Task[TaskId]->TaskUdpNo].sockfd = INVALID_SOCKET; Sleep(100); continue; } //2.绑定端口 SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_port = htons((WORD)udpsockfd[Task[TaskId]->TaskUdpNo].LocalUdpPort); addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); int len = sizeof(sockaddr); ret = bind(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd,(sockaddr*)&addr,len); //绑定后,只接收绑定设置的报文 if(ret==SOCKET_ERROR) { shutdown(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, 2); ::closesocket(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd); udpsockfd[Task[TaskId]->TaskUdpNo].sockfd = INVALID_SOCKET; Sleep(100); continue; } //3.加入多播组 ip_mreq mcast; mcast.imr_interface.S_un.S_addr=INADDR_ANY; //mcast.imr_multiaddr.S_un.S_addr=inet_addr("236.8.8.8"); inet_pton(AF_INET, "236.8.8.8", (void*)&mcast.imr_multiaddr.S_un); if(setsockopt(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcast,sizeof(mcast))) { ::shutdown(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, 2); ::closesocket(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd); udpsockfd[Task[TaskId]->TaskUdpNo].sockfd = INVALID_SOCKET; Sleep(100); continue; } //4.设置组播数据不回环 int loop=0;//1为数据回环 ret = ::setsockopt(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)&loop,sizeof(loop)); if(ret == SOCKET_ERROR) { ::shutdown(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, 2); ::closesocket(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd); udpsockfd[Task[TaskId]->TaskUdpNo].sockfd = INVALID_SOCKET; Sleep(100); continue; } unsigned long ul1 = 1; //非阻塞模式 ret = ::ioctlsocket(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, FIONBIO, (unsigned long*)&ul1); if(ret == SOCKET_ERROR) { ::shutdown(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, 2); ::closesocket(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd); udpsockfd[Task[TaskId]->TaskUdpNo].sockfd = INVALID_SOCKET; Sleep(100); continue; } //可以发送广播 if(::setsockopt(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, SOL_SOCKET, SO_BROADCAST,(char*)&ul1, sizeof (unsigned long))==SOCKET_ERROR) { ::shutdown(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd, 2); ::closesocket(udpsockfd[Task[TaskId]->TaskUdpNo].sockfd); udpsockfd[Task[TaskId]->TaskUdpNo].sockfd = INVALID_SOCKET; Sleep(100); continue; } udpsockfd[Task[TaskId]->TaskUdpNo].InitialTaskUdp = TRUE; udpsockfd[Task[TaskId]->TaskUdpNo].LocalIp = MyIpA;
-
接收组播报文:
UINT taskUdpRecvPkt( LPVOID pParam )
{
fd_set rdset,wrset;
int max_fd,inaddrlen;
struct sockaddr_in inaddr;
BYTE i,TaskId = (BYTE)(LONG_PTR)pParam;
struct timeval to, to_wait;if(g_UdpRECV_Has_Create)return 1; //接收线程只创建1个
g_UdpRECV_Has_Create = TRUE;bThreadBusy[LIMIT_TASK_NUM*3-1]=TRUE;
while (true)
{
if(bThreadExit)break;FD_ZERO(&rdset); FD_ZERO(&wrset); max_fd = -1; for(i=0;i<MAX_UDP_NUM_TASK;i++) //多个udp接收,逐个判断 { if(i==UDP_NO_TASKFSA31C || i==UDP_NO_TASKFSA31C_B)continue; if(udpsockfd[i].InitialTaskUdp) { FD_SET(udpsockfd[i].sockfd, &rdset); FD_SET(udpsockfd[i].sockfd, &wrset); if(max_fd < (int)udpsockfd[i].sockfd) max_fd = (int)udpsockfd[i].sockfd; } } if(max_fd < 0 ){ Sleep(1000); //没有可用连接,等待1秒钟. continue; } to.tv_sec = 0; to.tv_usec = 5000; //5ms int status = select(max_fd+1, &rdset, &wrset,NULL, &to); if(status == 0) { // select timeout. continue; } else if((status < 0) && (errno ==EINTR)) { continue; } else if(status < 0) { perror("process_data_via_udp select error"); return 1; } //有报文进来,开始接收 for(i=0;i<MAX_UDP_NUM_TASK;i++) //多个udp接收,逐个判断 { if(i==UDP_NO_TASKFSA31C || i==UDP_NO_TASKFSA31C_B)continue; if(udpsockfd[i].InitialTaskUdp && (FD_ISSET(udpsockfd[i].sockfd, &rdset))) { int rx_len = recvfrom(udpsockfd[i].sockfd, (char*)&g_RecvUdpPkt[g_Net_UDPNrRec_Buf_Item_In_Pt].m_Buffer[0], MAX_NET_RECV_BUFFER_SIZE, 0, (struct sockaddr*)&inaddr, &inaddrlen); if((rx_len > 0)/* && (udpsockfd[i].MyIp != inaddr.sin_addr.s_addr)*/) { g_RecvUdpPkt[g_Net_UDPNrRec_Buf_Item_In_Pt].m_RecvIP = htonl(inaddr.sin_addr.s_addr); g_RecvUdpPkt[g_Net_UDPNrRec_Buf_Item_In_Pt].m_RecvLen = rx_len; g_RecvUdpPkt[g_Net_UDPNrRec_Buf_Item_In_Pt].m_UDPPORT = udpsockfd[i].LocalUdpPort; g_Net_UDPNrRec_Buf_Item_In_Pt++; if(g_Net_UDPNrRec_Buf_Item_In_Pt >= MAX_NET_RECV_UDP_ITEM_NUM) { g_Net_UDPNrRec_Buf_Item_In_Pt = 0; } } } } to_wait.tv_sec = 0; to_wait.tv_usec = 2000; //sleep select(0, NULL, NULL, NULL, &to_wait); //sleep 2 ms.
}
for(i=0;i<MAX_UDP_NUM_TASK;i++)
{
if(i==UDP_NO_TASKFSA31C || i==UDP_NO_TASKFSA31C_B)continue;if(udpsockfd[i].sockfd != INVALID_SOCKET) { shutdown(udpsockfd[i].sockfd, 2); ::closesocket(udpsockfd[i].sockfd); udpsockfd[i].sockfd = INVALID_SOCKET; }
}
bThreadBusy[LIMIT_TASK_NUM*3-1]=FALSE;
return 0;
}