zoukankan      html  css  js  c++  java
  • 五十八、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 }

      编译运行:

      

  • 相关阅读:
    获取指定函数的函数名称(用于兼容IE)
    opa gatekeeper笔记:AdmissionReview input.request请求对象结构
    团队内部密码共享方案:KeePassXC+微盘(企业微信)
    一个简单的golang项目,实验 gitlab-ci-cd Pipelines
    调用企业微信API拨打紧急通知电话
    使用PAM模块实现普通用户之间su免密切换
    thin_check命令 man手册
    Nginx server_name翻译
    UDP端口检查告警SHELL脚本(企业微信版机器人版)
    从零搭建vsftpd
  • 原文地址:https://www.cnblogs.com/kele-dad/p/10513272.html
Copyright © 2011-2022 走看看