浅墨浓香

想要天亮进城,就得天黑赶路。

导航

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

Posted on 2017-04-06 15:40  浅墨浓香  阅读(424)  评论(0编辑  收藏  举报

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\n");
        close(sockfd);
        exit(1);
    }
}

int main(int argc, char* argv[])
{
    if(argc < 2){
        fprintf(stderr, "usage: %s port\n", 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\n", 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\n", 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...\n");
    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\n");
    }

    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
 */