多播基于udp,让路由器复制数据包传递
基本和udp 程序一样
不同的地方:
对于发送者重要的 ,
1 发送数据不再直接发送到对端,而是发送到多播地址, 但端口还是对端的端口(否则对端套接字无法接受到数据),
这样通过路由器复制再转发, 对端recvfrom 的ip 将是路由器
2 多播ttl (默认1, 还是修改一下保险一些);
send_addr.sin_addr.s_addr = inet_addr(ipaddr); //多播地址
send_addr.sin_port = htons(port); //对端端口
DWORD ttl = 64; //设置多播ttl,默认是1 有可能不太够用
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,(char*)&ttl,sizeof(ttl));
对于接受方 :
1 由于是多播,由路由器复制并传递, 所以接受到的ip地址一般来说是路由器.
2 需要bind一下port 用于接受数据,
再来就是socket需要通过 setsockopt 加入多播组,否则无法接受多播组的信息
以上2点代码示意:
// bind ip,port , 否则无法接受数据
if (bind(sock, (SOCKADDR*)&local_addr, sizeof(local_addr)) == SOCKET_ERROR){
print_error(WSAGetLastError());
return 0;
}
//多播结构
IP_MREQ join_addr;
join_addr.imr_interface.s_addr = INADDR_ANY; //加入多播的主机,一般来说就是本机
join_addr.imr_multiaddr.s_addr = inet_addr(ip); //需要加入的多播地址
//通过 IP_ADD_MEMBERSHIP 让socket 加入多播
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&join_addr, sizeof(join_addr));
全部代码:
multi_sender.c
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
char ipaddr[16];
int port = 0;
scanf(" %s %d", ipaddr,&port);
SOCKADDR_IN send_addr;
printf("ip:%s\n", ipaddr);
memset(&send_addr, 0, sizeof(send_addr));
send_addr.sin_addr.s_addr = inet_addr(ipaddr); //发往多播地址
send_addr.sin_port = htons(port); //接受方的端口
send_addr.sin_family = AF_INET;
DWORD ttl = 64;
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,(char*)&ttl,sizeof(ttl));
char buf[100] = "fuck you";
for (int i = 0; i < 3; ++i){
sendto(sock, buf, strlen(buf), 0, (SOCKADDR*)&send_addr, sizeof(send_addr));
Sleep(1000);
}
closesocket(sock);
WSACleanup();
mutli_recver.c
char ip[16];
unsigned short port = 0;
scanf(" %s %hd", ip, &port);
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_addr.s_addr = INADDR_ANY;
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(port); //接受的端口号
if (bind(sock, (SOCKADDR*)&local_addr, sizeof(local_addr)) == SOCKET_ERROR){
print_error(WSAGetLastError());
return 0;
}
//加入多播的结构
IP_MREQ join_addr;
join_addr.imr_interface.s_addr = INADDR_ANY; //本机所有接口
join_addr.imr_multiaddr.s_addr = inet_addr(ip); //加入多播地址
//通过IP_ADD_MEMBERSHIP 加入多播组
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&join_addr, sizeof(join_addr));
char buf[100];
SOCKADDR_IN client_addr;
int cli_len = sizeof(client_addr);
memset(&client_addr, 0, cli_len);
int n = 0;
while (1){
cli_len = sizeof(client_addr);
n = recvfrom(sock, buf, sizeof(buf), 0, (SOCKADDR*)&client_addr, &cli_len);
if (n == 0){
puts("peer closed");
break;
}
else if (n == SOCKET_ERROR){
print_error(WSAGetLastError());
break;
}
else {
buf[n] = 0;
printf("buf:%s, ip from : %s ,port:%d\n", buf,inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
}
}
WSACleanup();
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。