五十八、linux 编程——UDP 编程 广播

时间:2022-11-13 16:32:39

58.1 广播介绍

58.1.1 介绍

  • 广播实现一对多的通讯
  • 它通过向广播地址发送数据报文实现的

  五十八、linux 编程——UDP 编程 广播

58.1.2 套接字选项

  • 套接字选项用于修饰套接字以及其底层通讯协议的各种行为。函数 setsockopt 和 getsockopt 可以查看和设置套接字的各种选项。

  五十八、linux 编程——UDP 编程 广播

  • optname 选项
    • SO_BROADCAST 选项控制着 UDP 套接字是否能够发送广播数据报,选项的类型为 int, 非0 意味着 ”是“,注意,只有 UDP 套接字可以使用这个选项, TCP 是不能使用广播的

  五十八、linux 编程——UDP 编程 广播

  • optname 选项
    • SO_SNDBUF 和 SO_RCVBUF:每一个套接字有一个发送缓冲区和接收缓冲区,这两个缓冲区由底层协议使用,接收缓冲区存放由协议接收的数据直到被应用程序读走,发送缓冲区存放应用写出的数据直到被协议发送出去。SO_SNDBUF 和 SO_RCVBUF 选项分别控制发送和接收缓冲区的大小,他们的类型均为 int,以字节为单位。

  五十八、linux 编程——UDP 编程 广播

  • getsockopt 去获取发送缓冲区的大小,缓冲区的大小存放在 opt 中
  • setsockopt 去扩大发送缓冲区的大小,缓冲区的大小由 opt 扩大
  • 一般采用默认,不需要修改

58.1.3 广播地址

  • 如果用 {netID, subnetID, hostID}({网络 ID, 子网 ID,主机 ID})表示 IPV4 地址,那么有四类的广播地址,我们用 -1 表示所有比特都为 1 的字段
  • 子网广播地址:{netID, subnetID, -1}。这类地址编排制定子网上的所有接口。例如,如果我们对 B 类地址 192.168 采用 8 位子网 ID,那么 192.168.2.255 将是 192.168.2 子网上所有接口的子网广播地址。路由器通常不转发这类广播。
  • 全部子网广播地址:{netID, -1, -1}。这类广播地址编排制定网络上的所有子网。如果说这类地址曾被用过的话,那么现在已很少见了。
  • 受限广播地址:{-1,-1,-1} 或 255.255.255.255。路由器从不转发目的地址 255.255.255.255 的 IP 数据报。

58.2 例子

58.2.1 接收者

 #include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h> int sockfd; void sig_handler(int signo)
{
if(signo == SIGINT){
printf("receiver will exited\n");
close(sockfd);
exit();
}
} int main(int argc, char *argv[])
{
if(argc < ){
fprintf(stderr, "usage: %s port\n", argv[]);
exit();
} if(signal(SIGINT, sig_handler) == SIG_ERR){
perror("signal sigint error");
exit();
} sockfd = socket(AF_INET, SOCK_DGRAM, );
if(sockfd < ){
perror("socket error");
exit();
} struct sockaddr_in serveraddr;
memset(&serveraddr, , sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[]));
serveraddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < ){
perror("bind error");
exit();
} char buffer[];
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
while(){
memset(buffer, , sizeof(buffer));
memset(&clientaddr, , sizeof(clientaddr));
if(recvfrom(sockfd, buffer, sizeof(buffer), , (struct sockaddr*)&clientaddr, &len) < ){
perror("recvfrom error");
exit();
}
else {
char ip[];
inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ip, sizeof(ip));
int port = ntohs(clientaddr.sin_port);
printf("%s(%d): %s\n", ip, port, buffer);
}
} return ;
}

58.2.2 发送者

 #include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h> int main(int argc, char *argv[])
{
if(argc < ){
fprintf(stderr, "usage: %s ip port\n", argv[]);
exit();
} int sockfd = socket(AF_INET, SOCK_DGRAM, );
if(sockfd < ){
perror("socket error");
exit();
} int opt = ;
/** 采用广播方式发送 */
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)); struct sockaddr_in serveraddr;
memset(&serveraddr, , sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[]));
inet_pton(AF_INET, argv[], &serveraddr.sin_addr.s_addr); printf("I will broadcast...\n");
char *info = "hello world";
ssize_t size = strlen(info) * sizeof(char);
if(sendto(sockfd, info, size, , (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < ){
perror("sendto error");
exit();
}
else{
printf("broadcast success\n");
} close(sockfd); return ;
}

  编译运行:

  五十八、linux 编程——UDP 编程 广播