1.初始化Socket
bool InitRecvMulticast(SOCKET &iSocktet, QString &iLocalIp, int &iRecvProt, QString &iRecvMulticastIp, QString &iRecvPubMulticastIp)
{
	WSADATA wsaData;
	if (iSocktet)
	{
		closesocket(iSocktet)
	}
	if (!m_IsWSAStartup.load()) 
	{
		if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 
		{
			return false;
		}
		else 
		{
			m_IsWSAStartup.store(true);
		}
	}
	iSocktet = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (iSocktet == INVALID_SOCKET)
	{
		LOG(ERROR) << "recv socket create error: " << WSAGetLastError();
		return false;
	}
	sockaddr_in my_addr;
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(iRecvProt);
	my_addr.sin_addr.S_un.S_addr = inet_addr(iLocalIp.toLocal8Bit().data());
	if (::bind(iSocktet, (SOCKADDR *)&my_addr, sizeof(my_addr)) == SOCKET_ERROR) 
	{
		LOG(ERROR) << "recv socket bind error: " << WSAGetLastError() << "  ip =" << iLocalIp.toLocal8Bit().data();
		return false;
	}
	struct ip_mreq mreq;
	mreq.imr_multiaddr.s_addr = inet_addr(iRecvMulticastIp.toLocal8Bit().data());
	mreq.imr_interface.s_addr = inet_addr(iLocalIp.toLocal8Bit().data());    //指定接口接收组播信息
	if (!setsockopt(iSocktet, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq)))
	{
 		qDebug() << QString::fromLocal8Bit("加入组播:%1成功").arg(iRecvMulticastIp);
		LOG(INFO) << QString::fromLocal8Bit("加入组播:%1成功").arg(iRecvMulticastIp).toLocal8Bit().data();
	}
	else 
	{
		LOG(ERROR) << QString::fromLocal8Bit("加入组播:%1失败").arg(iRecvMulticastIp).toLocal8Bit().data();
		return false;
	}

	if (m_IsUsedPub == 1 && iRecvMulticastIp != iRecvPubMulticastIp && !iRecvPubMulticastIp.isEmpty()) 
	{
		struct ip_mreq pub_mreq;
		pub_mreq.imr_multiaddr.s_addr = inet_addr(iRecvPubMulticastIp.toLocal8Bit().data());
		pub_mreq.imr_interface.s_addr = inet_addr(iLocalIp.toLocal8Bit().data());    //指定接口接收组播信息
		if (!setsockopt(iSocktet, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&pub_mreq, sizeof(pub_mreq)))
		{
 			qDebug() << QString::fromLocal8Bit("加入组播:%1成功").arg(iRecvPubMulticastIp);
			LOG(INFO) << QString::fromLocal8Bit("加入组播:%1成功").arg(iRecvPubMulticastIp).toLocal8Bit().data();
		}
		else
		{
			LOG(ERROR) << QString::fromLocal8Bit("加入组播:%1失败").arg(iRecvPubMulticastIp).toLocal8Bit().data();
			return false;
		}
	}
	//设置接收超时时间
	struct timeval overTime;
	overTime.tv_sec = 30000;
	overTime.tv_usec = 0;
	if (setsockopt(iSocktet, SOL_SOCKET, SO_RCVTIMEO, (char *)&overTime, sizeof(overTime)) < 0)
	{
		printf("socket option  SO_RCVTIMEO not support\n");
		return false;
	}
	return true;

}
2.接受udp数据
void recvUdpData(SOCKET &iSocktet, QString &iLocalIp, int &iRecvProt, QString &iRecvMulticastIp, QString &iRecvPubMulticastIp, int iRecvIndex)
{
	bool isConnect = false;
	if (InitRecvMulticast(iSocktet, iLocalIp, iRecvProt, iRecvMulticastIp, iRecvPubMulticastIp)) 
	{
		isConnect = true;
	}
	while (isConnect) 
	{
		char iRecvBuff[1024] = { '\0' };
		SOCKADDR_IN sendAddrIn;
		int ret = recvfrom(iSocktet, iRecvBuff, sizeof(iRecvBuff), 0, (sockaddr*)&sendAddrIn, &naddrLen);
		if (ret == EWOULDBLOCK || ret == EAGAIN)
		{
			continue;
		}
		else if (ret > 0)
		{
			QByteArray byteArray(recvBuff, recvDataSize);
			qDebug() << QStringLiteral("接收到的数据:") << byteArray.toHex();
		}
	}
	std::thread udpSocketThread([&] {
		recvUdpData(m_recv_socket_A, m_local_ip_A, m_transport_recv_port_A, m_local_Multicast_ip_A, m_local_Multicast_pub_ip_A, 1);
	});
	udpSocketThread.detach();
}
3.主函数
std::thread udpSocketThread([&] {
	recvUdpData(m_recv_socket_A, m_local_ip_A, m_transport_recv_port_A, m_local_Multicast_ip_A, m_local_Multicast_pub_ip_A, 1);
});
udpSocketThread.detach();
4.头文件
#include <windows.h>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <QSocketNotifier>
#pragma comment(lib, "ws2_32.lib")
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐