UDP 是否其他一对多的数据收发方式?
多播是向特定组的所有主机传输数据的方法,多播也称之为组播
多播数据传输的特点:
多播组是个 D 类地址 (224.0.0.0 - 239.255.255.255)
"加入多播组" 可理解为 UDP 网络程序进行的申请
发送多播数据的方式,与发送普通 UDP 数据的方式相同
加入同一个多播组的主机不一定在同一个网络
因此,必须设置多播数据的最多转发次数 (TTL)
IP_MULTICAST_TTL
IP_MULTICAST_IF
IP_MULTICAST_LOOP
IP_ADD_MEMBERSHIP
mul_tx.c
#include
#include
#include
#include
#include
int main()
{
int server = 0;
struct sockaddr_in addr = {0};
struct sockaddr_in remote = {0};
char buf[128] = "D.T.SoftWare\n";
int ttl = 0;
int loop = 0;
struct in_addr maddr = {0};
int len = 0;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8888);
remote.sin_family = AF_INET;
remote.sin_addr.s_addr = indet_adr("234.1.1.168");
remote.sin_port = htons(6666);
server = socket(PF_INET, SOCK_DGRAM, 0);
if(server < 0)
{
printf("server socket error\n");
return -1;
}
if(bind(server, (struct sockaddr*)&addr, sizeof(addr)) == -1)
{
printf("udp server bind error\n");
return -1;
}
len = sizeof(ttl);
getsockopt(server, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &len); // 组播的 TTL 默认为1,只能在本网段下进行组播消息的转发,如果需要将组播消息发送到别的网段上,则需要设置 TTL
printf("default ttl = %d\n", ttl);
ttl = 32;
len = sizeof(ttl);
setsockopt(server, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, len);
printf("current ttl = %d\n", ttl);
len = sizeof(ttl);
getsockopt(server, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &len);
printf("default loop = %d\n", loop);
/*
loop = 0;
len = sizeof(loop);
setsockopt(server, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, len); // loop 设置为0,则不会将组播消息发送给发送端所在的 IP 地址
printf("current loop = %d\n", loop);
*/
maddr.s_addr = inet_addr("192.168.197.128");
len = sizeof(maddr);
setsockopt(server, IPPROTO_IP, IP_MULTICAST_IF, &maddr, len); // 如果本台主机上有多个网口则需要设置是从哪个 IP 地址发送组播消息
len = sizeof(maddr);
getsockopt(server, IPPROTO_IP, IP_MULTICAST_IF, &maddr, &len);
printf("current IP = %s\n", inet_ntoa(maddr));
printf("udp server start success!\n");
while(1)
{
len = sizeof(remote);
sendto(server, buf, strlen(buf), 0, (struct sockaddr*)&remote, len);
sleep(1);
}
close(server);
return 0;
}
mul_rx.c
#include
#include
#include
#include
#include
int main()
{
int sock = 0;
struct sockaddr_in remote = {0};
struct sockaddr_in addr = {0};
struct ip_mreq group = {0};
char buf[128] = {0};
int r = 0;
socklen_t len = 0;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(6666);
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("client socket error\n");
return -1;
}
if(bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
printf("udp client bind errpr\n");
return -1;
}
group.imr_multiaddr.s_addr = inet_addr("234.1.1.168"); // 多播地址
group.imr_interface.s_addr = htonl(INADDR_ANY); // 加入多播组的主机地址,由操作系统来选定是哪一个 ip 地址
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));
while(1)
{
len = sizeof(remote);
r = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr*)&remote, &len);
if(r > 0)
{
buf[r] = 0;
printf("Receive: %s\n", buf);
}
else
{
break;
}
}
close(sock);
}
在实际项目中,因为多播数据的接收方和发送方可能不在同一个网络下,所以需要设置TTL,并且如果一个主机有多个网卡,最好直接指定好接收多播数据的IP地址,否则操作系统就会随机选择一个IP地址作为接收多播数据的地址,导致多播数据可能就接收不到了。
实验结果如下图所示:
单播:一对一数据发送,即:指定目标主机发送数据
广播
多播(组播)