UNP学习_UDP广播和组播服务器实现
1.1 广播概述
单播指的是一个进程只与另一个进程通信。TCP就只支持单播寻址,UDP和原始IP支持其他类型寻址。广播可以将UDP报文发送到子网内的全部节点(包括自己),是”一对所有“的通信模式。
广播与组播的要点:
(1)组播支持在IPv4中是可选的,IPv6中是必须的
(2)IPv6不支持广播,IPv4中的程序移植到IPv6需要把广播改为组播
(2)广播和组播要求用与UDP和原始IP,不能用于TCP
下图是UNP书中P421给出的广播示例:
利用ifconfig命令可以看到广播地址Bcast:
1.2 UDP广播服务器示例代码:
// File Name: udp_server.c
// Author: AlexanderGan
// Created Time: 2020年08月11日 星期二 19时57分33秒
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<sys/stat.h>
int main(int argc, char*argv[]){
int fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd < 0){
perror("socket error!\n");
exit(1);
}
struct sockaddr_in serv_addr, client_addr;
socklen_t serv_len = sizeof(serv_addr);
socklen_t cli_len = sizeof(client_addr);
memset(&serv_addr,0,serv_len);
memset(&client_addr,0,cli_len);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(1234);
int ret = bind(fd,(struct sockaddr*)&serv_addr,serv_len);
if(ret < 0){
perror("bind error!\n");
exit(1);
}
//初始化客户端信息
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(1111);//客户端需要绑定的端口
inet_pton(AF_INET,"192.168.142.255",&client_addr.sin_addr.s_addr);
//打开服务器广播权限
int flag = 1;
setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&flag,sizeof(flag));
while(1){
//持续给客户端广播数据
static int num = 0;
char buf[4096] = {0};
sprintf(buf,"hello ,udp_id == %d\n",num++);
int send_len = sendto(fd,buf,sizeof(buf),0,(struct sockaddr*)&client_addr,cli_len);
if(send_len < 0){
perror("send error!\n");
exit(1);
}
printf("server send buf = %s\n",buf);
sleep(1);
/*char ip[64];
printf("New Client IP : %s, port = %d\n",
inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ip,sizeof(ip)),
ntohs(client_addr.sin_port));
sendto(fd,buf,strlen(buf)+1,0,(struct sockaddr*)&client_addr,cli_len);*/
}
close(fd);
return 0 ;
}
1.3 UDP广播客户端示例代码:
// File Name: udp_client.c
// Author: AlexanderGan
// Created Time: 2020年08月16日 星期日 19时06分28秒
// 广播客户端
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<sys/stat.h>
int main(int argc, char*argv[]){
int fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd < 0){
perror("socket error!\n");
exit(1);
}
//绑定IP和端口
struct sockaddr_in serv_addr, client_addr;
socklen_t serv_len = sizeof(serv_addr);
socklen_t cli_len = sizeof(client_addr);
memset(&client_addr,0,cli_len);
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(1111);
inet_pton(AF_INET,"0.0.0.0",&client_addr.sin_addr.s_addr);
int ret = bind(fd,(struct sockaddr*)&client_addr,cli_len);
if(ret < 0){
perror("bind error!\n");
exit(1);
}
//通信
while(1){
char buf[1024];
int recv = recvfrom(fd,buf,sizeof(buf),0,NULL,NULL);
if(recv < 0) {
perror("recv error!\n");
break;
}
printf("client recv buf =%s\n",buf);
}
close(fd);
return 0;
}
对发送接收函数不熟悉的同学可以看一下recvfrom函数原型和sendto函数原型。
1.4 广播的优缺点
优点:主机发送后,子网的所有主机都能接收到
缺点:同一子网的所有主机都要处理广播的数据报,若是UDP数据报则需要一直向上传递到UDP层,不需要这些数据报的主机如果在运行需要高速率处理的应用则容易带来过度的处理负担。