实际项目中,经常需要使用组播,代码示例如下:
服务端源码 服务端需要添加加入组播组的相关代码。
#include "stdafx.h" #include<WinSock2.h> #include<Ws2tcpip.h> //ip_mreq头文件 #include<iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") int _tmain(int argc, _TCHAR* argv[]) { WSADATA WSAData; WORD sockVersion=MAKEWORD(2,2); if(WSAStartup(sockVersion,&WSAData)!=0) return 0; SOCKET serSocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); //创建服务器socket if(INVALID_SOCKET==serSocket) { cout<<"socket error!"; return 0; } //设置传输协议、端口以及目的地址 sockaddr_in serAddr; serAddr.sin_family=AF_INET; serAddr.sin_port=htons(8888); serAddr.sin_addr.S_un.S_addr=INADDR_ANY; if(bind(serSocket,(sockaddr*)&serAddr,sizeof(serAddr))==SOCKET_ERROR) //将socket绑定地址 { cout<<"bind error"; closesocket(serSocket); return 0; } /* ip_mreq的定义 typedef struct ip_mreq { IN_ADDR imr_multiaddr; // IP multicast address of group. IN_ADDR imr_interface; // Local IP address of interface. } IP_MREQ, *PIP_MREQ; */ //加入组播组 ip_mreq multiCast; multiCast.imr_interface.S_un.S_addr=INADDR_ANY; //本地某一网络设备接口的IP地址。 multiCast.imr_multiaddr.S_un.S_addr=inet_addr("234.2.2.2"); //组播组的IP地址。 setsockopt(serSocket,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&multiCast,sizeof(multiCast)); sockaddr_in clientAddr; int iAddrlen=sizeof(clientAddr); char buff[1024]; //建立接收缓存字节数组 while(true) { memset(buff,0,1024); //清空接收缓存数组 //开始接收数据 int len=recvfrom(serSocket,buff,1024,0,(sockaddr*)&clientAddr,&iAddrlen); if(len>0) { cout<<"客户端地址:"<<inet_ntoa(clientAddr.sin_addr)<<endl; cout<<buff; // sendto(serSocket,buff,1024,0,(sockaddr*)&clientAddr,iAddrlen); } } closesocket(serSocket); //关闭socket WSACleanup(); return 0; }客户端源码 客户端变化不大,只是发送地址改为组播地址。
#include "stdafx.h" #include<WinSock2.h> #include<iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") int _tmain(int argc, _TCHAR* argv[]) { WSADATA WSAData; WORD sockVersion=MAKEWORD(2,2); if(WSAStartup(sockVersion,&WSAData)!=0) return 0; SOCKET clientSocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if(INVALID_SOCKET==clientSocket) { cout<<"socket error!"; return 0; } sockaddr_in dstAddr; dstAddr.sin_family=AF_INET; dstAddr.sin_port=htons(8888); dstAddr.sin_addr.S_un.S_addr=inet_addr("234.2.2.2"); const char* sendData="来自客户端的数据包。"; sendto(clientSocket,sendData,strlen(sendData),0,(sockaddr*)&dstAddr,sizeof(dstAddr)); closesocket(clientSocket); WSACleanup(); return 0; }服务端代码:
use std::net::UdpSocket; use std::net::Ipv4Addr; fn main() { let mut socket = UdpSocket::bind("0.0.0.0:8888").unwrap(); let mut buf = [0u8; 65535]; let multi_addr = Ipv4Addr::new(234, 2, 2, 2); let inter = Ipv4Addr::new(0,0,0,0); socket.join_multicast_v4(&multi_addr,&inter); loop { let (amt, src) = socket.recv_from(&mut buf).unwrap(); println!("received {} bytes from {:?}", amt, src); } }客户端代码:
use std::net::UdpSocket; use std::thread; fn main() { let socket = UdpSocket::bind("0.0.0.0:9999").unwrap(); let buf = [1u8; 15000]; let mut count = 1473; socket.send_to(&buf[0..count], "234.2.2.2:8888").unwrap(); thread::sleep_ms(1000); }组播是一种数据包传输方式,当有多台主机同时成为一个数据包的接受者时,出于对带宽和CPU负担的考虑,组播成为了一种最佳选择。
组播通过把224.0.0.0-239.255.255.255的D类地址作为目的地址,有一台源主机发出目的地址是以上范围组播地址的报文,在网络中,如果有其他主机对于这个组的报文有兴趣的,可以申请加入这个组,并可以接受这个组,而其他不是这个组的成员是无法接受到这个组的报文的。
众所周知的D类IP地址:
D类地址用途224.0.0.1在一个子网上的所有主机224.0.0.2在一个子网上的所有路由器224.0.0.4所有DVMRP协议的路由器224.0.0.5所有开放最短路径优先(OSPF)路由器224.0.0.6所有OSPF指定路由器224.0.0.9所有RIPv2路由器224.0.0.13所有PIM协议路由器224.0.0.0-224.0.0.255保留作本地使用,做管理和维护任务239.0.0.0-239.255.255.255留用做管理使用最后,欢迎关注个人微信公众号,Let’s go!