问题
如何进行一对多的 UDP 数据发送?
UDP 通信中的广播
广播是向同一网络中的所有主机传输数据的方法
广播类型
- 直接广播: IP 地址中除网络地址外,其余主机地址均设置为1
- 本地广播: 无须知道网络地址,255.255.255.255作为 IP 地址使用
区别:
- 本地广播数据不经过路由器寻址,直接发送到本地主机
本地广播应用应用案例: DHCP
DHCP (动态主机配置协议) 是一个局域网的网络协议 (基于 UDP 协议)
- 本地主机可自动获取到服务器分配的 IP 地址和子网掩码
DHCP 采用 客户端/服务器 模型,地址的动态分配由网络主机驱动
工作方式:
- 当 DHCP 服务器接收到来自网络主机的目标申请时,会向网络主机发送相关的地址配置信息,以实现网络主机地址信息的动态配置
本地主机想要获取 IP 地址,首先会在本地广播一个数据包,源IP地址为0.0.0.0,目标IP地址为255.255.255.255,DHCP 服务器收到此数据包后,会回复本地主机;本地主机获取到的 IP 地址是有期限的,快到期限的时候,本地主机会继续广播,请求继续使用此 IP 地址。
预备工作 => socket 属性设置 (option)
socket 的本质是对本机网络资源的一种标识
socket 本身有各种属性 (不同的连接,属性可能不同)
通过 setsockopt() / getsockopt() 可存取指定 socket 的属性值
socket 属性的改变可造成 socket 数据收发行为的改变
TCP 编程中涉及的用法
setsockopt() / getsockopt() 属性存取函数
UDP 数据广播
编程实验
client.c
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
int main()
{
int server = 0;
struct sockaddr_in addr = {0};
struct sockaddr_in remote = {0};
char buf[128] = "D.T.SoftWare\n";
int len = 0;
int brd = 1;
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 = inet_addr("192.168.197.255");
// remote.sin_addr.s_addr = 0xFFFFFFFF;
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;
}
setsockopt(server, SOL_SOCKET, SO_BROADCAST, &brd, sizeof(brd));
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;
}
server.c
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
int main()
{
int sock = 0;
struct sockaddr_in remote = {0};
struct sockaddr_in addr = {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;
}
while(1)
{
len = sizeof(remote);
r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);
if(r > 0)
{
buf[r] = 0;
printf("Receive: %s\n", buf);
}
}
close(sock);
}
192.168.197.xxx网段下的所有6666端口的进程都能够收到广播。
思考
UDP 是否还有其他一对多的数据发送方式?