项目需求需要在windows2008 r2的环境上搭建虚拟机Linux系统,并用Linux系统接收组播数据。在windows2008 r2搭建虚拟机,已经介绍过了。关键的地方在与,桥接网卡,静态IP要设置好。 组播是基于IP/TCP协议簇下的多播协议(Internet组管理协议),也叫IGMP协议。组播程序的代码与UDP网络编程的代码有些许变化。 Windows接收端代码 #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #include #include"MdParser.h" #pragma comment(lib, “ws2_32.lib”) using namespace md_parser; int main() { int iRet = 0; WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); sockaddr_in addr; addr.sin_family = AF_INET; //addr.sin_addr.S_un.S_addr = INADDR_ANY; addr.sin_addr.S_un.S_addr = inet_addr("0.0.0.0"); addr.sin_port = htons(9411); bool bOptval = true; iRet = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptval, sizeof(bOptval)); if (iRet != 0) { printf("setsockopt fail:%d", WSAGetLastError()); return -1; } iRet = bind(sock, (sockaddr*)&addr, sizeof(addr)); if (iRet != 0) { printf("bind fail:%d", WSAGetLastError()); return -1; } printf("socket:%d bind success\n", sock); // 加入组播 ip_mreq multiCast; //multiCast.imr_interface.S_un.S_addr = INADDR_ANY; multiCast.imr_interface.S_un.S_addr = inet_addr("0.0.0.0"); multiCast.imr_multiaddr.S_un.S_addr = inet_addr("234.2.2.2"); iRet = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multiCast, sizeof(multiCast)); if (iRet != 0) { printf("setsockopt fail:%d", WSAGetLastError()); return -1; } printf("udp group start\n"); int len = sizeof(sockaddr); char strRecv[512] = { 0 }; while (true) { memset(strRecv, 0, sizeof(strRecv)); iRet = recvfrom(sock, strRecv, sizeof(strRecv) - 1, 0, (sockaddr*)&addr, &len); if (iRet <= 0) { printf("recvfrom fail:%d", WSAGetLastError()); return -1; } printf("%s\n",strRecv); } closesocket(sock); } Windows发送端代码: #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, “ws2_32.lib”) int main() { int iRet = 0; WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); sockaddr_in addr; addr.sin_addr.S_un.S_addr = inet_addr("234.2.2.2"); addr.sin_family = AF_INET; addr.sin_port = htons(9411); char strSend[1024] = { 0 }; static int iIdx = 0; while (1) { sprintf_s(strSend, "udp send group data:%d", iIdx++); iRet = sendto(sock, strSend, strlen(strSend) + 1, 0, (sockaddr*)&addr, sizeof(sockaddr)); if (iRet <= 0) { printf("send fail:%d", WSAGetLastError()); } else { printf("send data:%s\n", strSend); } Sleep(512); } closesocket(sock); WSACleanup(); return 0; } 在Windows环境下直接编译运行即可通过。但是在Linux系统无论是真实环境,还是虚拟机环境直接运行组播是接收不到数据的。需要抓包配置相应的网络环境,可以通过以下步骤检查网络环境。 1.检查Linux系统的防火墙是否关闭; 关闭防火墙的命令: sudo systemctl stop firewalld 临时关闭 sudo systemctl disable firewalld ,然后reboot 永久关闭 sudo systemctl status firewalld 查看防火墙状态 查看防火墙是否关闭: Systemctl status firewalld.service 若看到标注为active(running)则防火墙是开启状态。如果出现disactive(dead)的字样,说明防火墙已经关闭。 2.若关闭防火墙不能解决问题,则需要抓包,看一下路由转发的IGMP包的协议版本,将本地的IGMP包的协议版本改为路由器转发的一样即可。 3.最关键的一步是添加组播路由到本地的路由表中,在Windows系统下,这一步是由系统自动完成的,Linux好像需要自己配置。 添加路由命令: route add -net 224.0.0.0 netmask 240.0.0.0 ens33(需要组播的网卡) route add -net 0.0.0.0 netmask 0.0.0.0 ens33 4.将组播程序中的本地地址改为0.0.0.0即可 (责任编辑:IT) |