• 第14章 UDP编程(3)_利用UDP实现广播功能


    3. 广播的介绍

    (1)广播

      ①广播实现一对多的通信,如QQ群

      ②它通过向广播地址发送数据报文实现的

    (2)SO_BROADCAST选项

      ①SO_BROADCAST选项控制着UDP套接字是否能发送广播数据报,选项的类型为int,非零意味着“是”。

      ②注意,该选项只有UDP套接字可以使用,TCP是不能使用广播的

    (3)其它选项:SO_SNDBUFSO_RCVBUF选项

      ①每一个套接字有一个发送缓冲区和接收缓冲区,这两个缓冲区由底层协议使用。

      ②接收缓冲区存放由协议接收的数据直到被应用程序读走发送缓冲区存放应用写出的数据直接被协议发送出去

      ③SO_SNDBUF和SO_RCVBUF选项分别控制发送和接收缓冲区的大小,他们的类型均为int,以字节为单位。

    (4)广播地址

      ①如果用{netID, subnetID, hostID}来表示IPv4地址,那么有四类的广播地址,用-1表示所有比特都为1的字段。

      ②子网广播地址:{netID, subnetID, -1}。这类地址编排指定子网上的所有接口。例如,如果我们对C类地址192.168采用8位子网ID,那么192.168.2.255将是192.168.2子网上所有接口的子网广播地址路由器通常不转发这类广播

      ③全部子网广播地址{netID,-1,-1}。这类广播地址编排指定网络上的所有子网。现在很少这样用。

      ④受限广播地址:{-1,-1,-1,-1}或{255,255,255,255}。路由器从不转发目的地址为255.255.255.255的IP数据报。

    【编程实验】利用UDP发送广播(多对多或一对多)

    //receiver.c

    #include <netdb.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <signal.h>
    #include <memory.h>
    
    int sockfd;
    
    void sig_handler(int signo)
    {
        if(signo == SIGINT){
            printf("receiver will exit
    ");
            close(sockfd);
            exit(1);
        }
    }
    
    int main(int argc, char* argv[])
    {
        if(argc < 2){
            fprintf(stderr, "usage: %s port
    ", argv[0]);
            exit(1);
        }
    
        if(signal(SIGINT, sig_handler) == SIG_ERR){
            perror("signal sigint error");
            exit(1);
        }
    
        //创建套接字
        sockfd = socket(AF_INET, SOCK_DGRAM, 0); //UDP协议
        if(sockfd < 0){
            perror("socket error");
            exit(1);
        }
    
        //绑定地址,以便在指定的端口上接收广播
        struct sockaddr_in recvAddr;
        memset(&recvAddr, 0, sizeof(recvAddr));
        recvAddr.sin_family = AF_INET; //IPv4
        recvAddr.sin_port = htons(atoi(argv[1])); //port
        recvAddr.sin_addr.s_addr = INADDR_ANY; //由系统指定IP
    
        if(bind(sockfd, (struct sockaddr*)&recvAddr, sizeof(recvAddr)) < 0){
            perror("bind error");
            exit(1);
        }
    
        //接收广播消息
        char buff[1024];
        struct sockaddr_in sendAddr;
        socklen_t len = sizeof(sendAddr);
        while(1){
            memset(buff, 0, sizeof(buff));
            memset(&sendAddr, 0, sizeof(sendAddr));
            if(recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr*)&sendAddr, &len) < 0){
                perror("recvfrom error");
                exit(1);
            }else{
                char ip[16];
                inet_ntop(AF_INET, &sendAddr.sin_addr.s_addr, ip, sizeof(ip));
                int port = ntohs(sendAddr.sin_port);
                printf("%s(%d): %s
    ", ip, port, buff);
            }
    
        }
    }
    /*输出结果
     [root@localhost 14.udp]# gcc -o bin/broadcast src/broadcast.c 
     [root@localhost 14.udp]# bin/receiver 
     usage: bin/receiver port
     [root@localhost 14.udp]# bin/receiver 8888
     192.168.32.100(40894): hello world!
     192.168.32.100(33915): hello world!
     192.168.32.100(48427): hello world!
     ^Creceiver will exit
     */

    //broadcast.c

    #include <netdb.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <memory.h>
    
    int main(int argc, char* argv[])
    {
        if(argc < 3){
            fprintf(stderr, "usage: %s ip port
    ", argv[0]);
            exit(1);
        }
    
        //创建套接字
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0); //UDP协议
        if(sockfd < 0){
            perror("socket error");
            exit(1);
        }
    
        //设置为广播方式发送消息
        int opt = 1;
        setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
    
        struct  sockaddr_in recvAddr;  //指定广播的接收者地址信息。
        memset(&recvAddr, 0, sizeof(recvAddr));
        recvAddr.sin_family = AF_INET;
        recvAddr.sin_port = htons(atoi(argv[2])); //注意,不指定IP(广播为255),只说明接收者的端口
        inet_pton(AF_INET, argv[1], &recvAddr.sin_addr.s_addr);
    
        printf("I will broadcast...
    ");
        char* info = "hello world!";
        size_t size = strlen(info)* sizeof(char);
        if(sendto(sockfd, info, size, 0, (struct sockaddr*)&recvAddr, sizeof(recvAddr)) < 0){
            perror("sendto error");
            exit(1);
        }else{
            printf("broadcast success
    ");
        }
    
        close(sockfd);
    
        return 0;
    }
    /*输出结果
     * [root@localhost 14.udp]# bin/broadcast 192.168.32.100 8888
     * I will broadcast...
     * broadcast success
     * [root@localhost 14.udp]# bin/broadcast 192.168.32.100 8888
     * I will broadcast...
     * broadcast success
     * [root@localhost 14.udp]# bin/broadcast 192.168.32.100 8888
     * I will broadcast...
     * broadcast success
     */
  • 相关阅读:
    Java:抽象类与接口
    OOP编程思想:类的设计原则
    Win10系统下设置Go环境变量和go语言开启go module
    Windows下Golang安装Iris框架
    AOS.JS 和基于Animation.css的收费库WOW.JS相似
    文本比价工具
    MySQL Order By Rand()效率
    datatable分页
    PHP面向对象之魔术方法
    PHP面向对象之序列化与反序列化
  • 原文地址:https://www.cnblogs.com/5iedu/p/6673768.html
Copyright © 2020-2023  润新知