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

58.1 广播介绍

58.1.1 介绍

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

  

58.1.2 套接字选项

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

  

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

  

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

  

  • 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 接收者

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <netdb.h>
 4 #include <signal.h>
 5 #include <string.h>
 6 #include <unistd.h>
 7 #include <sys/socket.h>
 8 #include <arpa/inet.h>
 9 
10 
11 int sockfd;
12 
13 void sig_handler(int signo)
14 {
15     if(signo == SIGINT){
16         printf("receiver will exited
");
17         close(sockfd);
18         exit(1);
19     }
20 }
21 
22 int main(int argc, char *argv[])
23 {
24     if(argc < 2){
25         fprintf(stderr, "usage: %s port
", argv[0]);
26         exit(1);
27     }
28 
29     if(signal(SIGINT, sig_handler) == SIG_ERR){
30         perror("signal sigint error");
31         exit(1);
32     }
33 
34     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
35     if(sockfd < 0){
36         perror("socket error");
37         exit(1);
38     }
39 
40     struct sockaddr_in serveraddr;
41     memset(&serveraddr, 0, sizeof(serveraddr));
42     serveraddr.sin_family = AF_INET;
43     serveraddr.sin_port = htons(atoi(argv[1]));
44     serveraddr.sin_addr.s_addr = INADDR_ANY;
45     if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){
46         perror("bind error");
47         exit(1);
48     }
49 
50     char buffer[1024];
51     struct sockaddr_in clientaddr;
52     socklen_t len = sizeof(clientaddr);
53     while(1){
54         memset(buffer, 0, sizeof(buffer));
55         memset(&clientaddr, 0, sizeof(clientaddr));
56         if(recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientaddr, &len) < 0){
57             perror("recvfrom error");
58             exit(1);
59         }
60         else {
61             char ip[16];
62             inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ip, sizeof(ip));
63             int port = ntohs(clientaddr.sin_port);
64             printf("%s(%d): %s
", ip, port, buffer);
65         }
66     }
67 
68     return 0;
69 }

58.2.2 发送者

 1 #include <netdb.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 #include <unistd.h>
 6 #include <sys/socket.h>
 7 #include <arpa/inet.h>
 8 
 9 
10 int main(int argc, char *argv[])
11 {
12     if(argc < 3){
13         fprintf(stderr, "usage: %s ip port
", argv[0]);
14         exit(1);
15     }
16 
17     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
18     if(sockfd < 0){
19         perror("socket error");
20         exit(1);
21     }
22 
23     int opt = 1;
24     /** 采用广播方式发送 */
25     setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
26 
27     struct sockaddr_in serveraddr;
28     memset(&serveraddr, 0, sizeof(serveraddr));
29     serveraddr.sin_family = AF_INET;
30     serveraddr.sin_port = htons(atoi(argv[2]));
31     inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);
32 
33     printf("I will broadcast...
");
34     char *info = "hello world";
35     ssize_t size = strlen(info) * sizeof(char);
36     if(sendto(sockfd, info, size, 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){
37         perror("sendto error");
38         exit(1);
39     }
40     else{
41         printf("broadcast success
");
42     }
43 
44     close(sockfd);
45 
46     return 0;
47 }

  编译运行:

  

原文地址:https://www.cnblogs.com/kele-dad/p/10513272.html