Question: Is there any other way of sending one-to-many data with UDP?
Multicast in UDP communication
Multicast is 向特定组中的所有主机传输数据的方法
, multicast is also called multicast
Features of multicast data transmission:
- The multicast sender only sends data once for a specific multicast group, and all hosts in the group can receive the data
- A host joins a specific group to receive multicast data in that group
- Multicast groups can be added arbitrarily within the IP address range
Key question: how to send and receive multicast data
A multicast group is a D
class address (224.0.0.0 - 239.255.255.255)
"Joining a multicast group" can be understood as an application made by a UDP network program
- For example: apply to receive multicast data sent to 239.234.111.222
- ie: set properties (
IPPROTO_IP, IP_ADD_MEMBERSHP
)
The way to send multicast data is the same as the way to send normal UDP data
- Preliminary operation: set properties, such as: (
IPPROTO_IP, IP_MULTICAST_TTL
)
Precautions
Hosts joining the same multicast group are not necessarily in the same network. Therefore, the maximum forwarding times (TTL) of multicast data must be set
- TTL (ie: Time To Live) is the main factor that determines the distance of data transmission
- TTL is expressed as an integer and is decremented by 1 for every route passed
- When the TTL becomes 0, the data cannot continue to be transmitted and can only be destroyed
Multicast Programming: Sending Side
IP_MULTCAST_TTL: used to set the "maximum transmission distance" of multicast data, default 1
IP_MULTICAST_IF: Used to set the network interface (network card) from which multicast data is sent, default: 0.0.0.0
默认 0.0.0.0 情况下操作系统会自主选择使用哪个网络接口,但在[多网卡主机]的[实际工程应用]中,最好手工指定!!
IP_MULTCAST_LOOP: Used to set whether multicast data is sent back to this machine, the default is 1 (1, sent back to this machine)
remote.sin_family = AF_INET;
remote.sin_addr.s_addr = inet_addr("224.1.1.168");
remote.sin_port = htons(8888);
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
do {
len = sizeof(remote);
r = sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&remote, len);
sleep(1);
}while(r > 0);
Multicast Programming: Receiver
IP_ADD_MEMBRESHIP: used to apply to join a multicast group, the parameters are: multicast group and local address
struct ip_mreq {
// group address
struct in_addr inmr_multiaddr;
// local host address
struct in_addr imr_interface
}
👇
struct ip_mreq group = {0};
group.imr_multiaddr.s_addr = inet_addr("224.1.1.168");
group.imr_interface.s_addr = htonl(INADDR_ANY); // 监听所有网卡
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));
do {
len = sizeof(remote);
r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);
buf[r] = 0;
printf("r = %d\n", r);
printf("msg = %s\n", buf);
}while (r > 0)
Exit the multicast group
quit = setsockopt(sock, IP_PROTO_IP, IP_DROP_MEMBERSHIP, &group, sizeof(group));
if (quit == 0) {
break;
}
Programming Experiment: UDP Multicast Programming
mul_tx.c
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int sock = 0;
struct sockaddr_in remote = {0};
socklen_t len = 0;
char buf[128] = "D.T.Software";
struct in_addr addr = {0};
int ttl = 0;
int loop = 0;
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
printf("socket error\n");
return -1;
}
remote.sin_family = AF_INET;
remote.sin_addr.s_addr = inet_addr("224.1.1.168");
remote.sin_port = htons(8888);
//-------------------------
ttl = 0;
len = sizeof(ttl);
getsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &len); // 可以不设置,ttl 默认为 1
printf("default ttl = %d\n", ttl);
ttl = 32;
len = sizeof(ttl);
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, len);
printf("current ttl = %d\n", ttl);
loop = 0;
len = sizeof(loop);
getsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &len); // 可以不设置,ttl 默认为 1 ,即本机也会收到
printf("default loop = %d\n", loop);
// addr.s_addr = inet_addr("192.168.3.221"); // 具体指定使用哪一块网卡进行数据广播
addr.s_addr = htonl(INADDR_ANY); // 交由操作系统进行选择
len = sizeof(addr);
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, len); // 可以不设置,默认为 INADDR_ANY 即 "0.0.0.0", 交由操作系统选择使用哪个网卡
printf("current if = %s\n", inet_ntoa(addr)); // 当主机有多个网卡,在实际工程使用时,最好手工指定使用那块网卡广播数据
//-------------------------
while (1) {
len = sizeof(remote);
sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&remote, len);
sleep(1);
}
close(sock);
return 0;
}
mul_rx.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int server = 0;
struct sockaddr_in saddr = {0};
struct sockaddr_in remote = {0};
struct ip_mreq group = {0};
int len = 0;
char buf[32] = {0};
int r = 0;
server = socket(PF_INET, SOCK_DGRAM, 0);
if (server == -1) {
printf("server socket error");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
printf("udp server bind error\n");
return -1;
}
printf("udp server start sucess\n");
group.imr_multiaddr.s_addr = inet_addr("224.1.1.168");
group.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(server, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));
while (1) {
len = sizeof(remote);
r = recvfrom(server, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);
if (r > 0) {
buf[r] = 0;
printf("Recvive: %s\n", buf);
} else {
break;
}
}
close(server);
return 0;
}
summary
Unicast: one-to-one data transmission, that is: specify the target host to send data
Broadcast (must be the same LAN)
- Local broadcast: Local LAN broadcasts data, all hosts can receive data
- Direct broadcast: The specified network broadcasts data, and all hosts in the target network can receive the data
Multicast (multicast) (can be different from a local area network)
- Send data to the specified multicast address, and all hosts "subscribed" to this address can receive the data
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。