编译环境为: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;
}