zoukankan      html  css  js  c++  java
  • linux网络编程--广播与组播

    广播

      前面介绍的数据包发送方式只有一个接收方,称为单播

      如果发送给局域网中的所有主机,称为广播

      只有用户数据报(使用UDP协议)套接字才能广播

    广播地址:

      以192.168.1.0(255.255.255.0)网段为例,最大的主机地址192.168.1.255代表该网段的广播地址

      发送该地址的数据包被所有主机接收

      255.255.255.255在所有网段中都代表广播地址

    广播发送

      创建用户数据报套接字

      缺省创建的套接字不允许广播数据包,需要设置属性--setsockopt可以设置套接字属性

      接收方指定为广播地址

      指定端口信息

      发送数据包

    设置套接口的选项:
      #include <sys/types.h>
      #include <sys/socket.h>
    int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
        sockfd:标识一个套接口的描述字。
        level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。
        optname:需设置的选项。
        optval:指针,指向存放选项待设置的新值的缓冲区
        optlen:optval缓冲区长度。
    成功返回0,失败返回-1并设置errno
    广播发送代码:
    sockfd=socket()
    ......
    int on=1
    setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
    .........
    sendto(....);

    广播接收:

    创建用户数据报套接字

    绑定ip地址(广播ip或0.0.0.0)和端口

      绑定的端口必须和发送方的指定的端口相同

    等待接收数据

    实例如下:

    send.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #define  err_log(errlog)  do{perror(errlog); exit(1);}while(0)
    #define   N  128
    
    // ./send 192.168.0.255 10000
    int main(int argc, const char *argv[])
    {
        int sockfd;
        struct sockaddr_in broadcastaddr;
        struct sockaddr_in clientaddr;
        socklen_t addrlen = sizeof(clientaddr);
        char buf[N] = {};
    
        if(argc < 3)
        {
            fprintf(stderr, "usage:%s serverip port.
    ", argv[0]);
            return -1;
        }
    
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        {
            err_log("fail to socket");
        }
    
        broadcastaddr.sin_family = AF_INET;
        broadcastaddr.sin_addr.s_addr = inet_addr(argv[1]);
        broadcastaddr.sin_port = htons(atoi(argv[2]));
    
        int on = 1;
    
        if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
        {
            err_log("fail to setsockopt");
        }
    
        while(1)
        {
            printf("Input > ");
            fgets(buf, N, stdin);
            buf[strlen(buf)-1] = '';
    
            if(sendto(sockfd, buf, N, 0, (struct sockaddr *)&broadcastaddr, addrlen) < 0)
            {
                err_log("fail to sendto");
            }
    
            if(strncmp(buf, "quit", 4) == 0)
            {
                break;
            }
    
            printf("%s
    ", buf);
    
        }
    
        close(sockfd);
    
        return 0;
    }

    recv.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #define  err_log(errlog)  do{perror(errlog); exit(1);}while(0)
    #define   N  128
    
    int main(int argc, const char *argv[])
    {
        int sockfd;
        struct sockaddr_in broadcastaddr;
        struct sockaddr_in clientaddr;
        socklen_t addrlen = sizeof(clientaddr);
        char buf[N] = {};
    
        if(argc < 3)
        {
            fprintf(stderr, "usage:%s serverip port.
    ", argv[0]);
            return -1;
        }
    
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        {
            err_log("fail to socket");
        }
    
        broadcastaddr.sin_family = AF_INET;
        broadcastaddr.sin_addr.s_addr = inet_addr(argv[1]);
        broadcastaddr.sin_port = htons(atoi(argv[2]));
    
        if(bind(sockfd, (struct sockaddr*)&broadcastaddr, sizeof(broadcastaddr)) < 0)
        {
            err_log("fail to bind");
        }
    
    
        while(1)
        {
            if(recvfrom(sockfd, buf, N, 0, (struct sockaddr*)&clientaddr, &addrlen) < 0)
            {
                err_log("fail to recvfrom");
            }
    
            printf("From clientaddr:%s
    ", buf);
            strcat(buf, " from server...");
    
        }
    
        close(sockfd);
    
    
        
        return 0;
    }

    编译运行测试

      ./send 192.168.1.255  10000

    分别在两台局域网内的机器上测试

    ./recv 192.168.1.255  10000 收到

    ./recv 192.168.1.255  10000 收到

    (2)组播(多播)

      单播方式只能发送给一个接收方

      广播方式发给所有的主机。过多的广播会大量占用网络带宽,造成广播风暴,影响正常通信

      组播(多播)是一种折中的方式只有加入某个多播组的主机才能收到数据

      多播方式既可以发送给多个主机,又能避免广播那样带来带来过多的负载(每台主机要到传输层才能判断广播包是否要处理)

    组播发送:

      创建用户数据报套接字

      接收方地址指定为组播地址

      指定端口信息

      发送数据包

    组播接收:

      创建用户数据报套接字

      加入多播组

      绑定ip地址(加入组的组ip或0.0.0.0)和端口---绑定的端口必须和发送方指定的端口相同

      等待接收数据

    加入多播组

    struct ip_mreq

    {

      struct in_addr imr_multiaddr;

      struct in_addr  imr_interface;

    }

       struct ip_mreq req;
      bzero(&req,sizeof(req)) req.imr_multiaddr.s_addr = inet_addr(argv[1]); req.imr_interface.s_addr = htonl(INADDR_ANY); if(setsockopt(sockfd, IPPROTO_IP,IP_ADD_MEMBERSHIP, &req, sizeof(req)) < 0) { err_log("fail to setsockopt"); }

     

    send.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #define  err_log(errlog)  do{perror(errlog); exit(1);}while(0)
    #define   N  128
    
    // ./send 192.168.0.255 10000
    int main(int argc, const char *argv[])
    {
        int sockfd;
        struct sockaddr_in groupcastaddr;
        struct sockaddr_in clientaddr;
        socklen_t addrlen = sizeof(clientaddr);
        char buf[N] = {};
    
        if(argc < 3)
        {
            fprintf(stderr, "usage:%s serverip port.
    ", argv[0]);
            return -1;
        }
    
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        {
            err_log("fail to socket");
        }
    
        groupcastaddr.sin_family = AF_INET;
        groupcastaddr.sin_addr.s_addr = inet_addr(argv[1]);
        groupcastaddr.sin_port = htons(atoi(argv[2]));
    
        while(1)
        {
            printf("Input > ");
            fgets(buf, N, stdin);
            buf[strlen(buf)-1] = '';
    
            if(sendto(sockfd, buf, N, 0, (struct sockaddr *)&groupcastaddr, addrlen) < 0)
            {
                err_log("fail to sendto");
            }
    
            if(strncmp(buf, "quit", 4) == 0)
            {
                break;
            }
    
            printf("%s
    ", buf);
    
        }
    
        close(sockfd);
    
        return 0;
    }

    recv.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #define  err_log(errlog)  do{perror(errlog); exit(1);}while(0)
    #define   N  128
    
    int main(int argc, const char *argv[])
    {
        int sockfd;
        struct sockaddr_in groupcastaddr;
        struct sockaddr_in clientaddr;
        socklen_t addrlen = sizeof(clientaddr);
        char buf[N] = {};
    
        if(argc < 3)
        {
            fprintf(stderr, "usage:%s serverip port.
    ", argv[0]);
            return -1;
        }
    
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        {
            err_log("fail to socket");
        }
    
        groupcastaddr.sin_family = AF_INET;
        groupcastaddr.sin_addr.s_addr = inet_addr(argv[1]);
        groupcastaddr.sin_port = htons(atoi(argv[2]));
    
        if(bind(sockfd, (struct sockaddr*)&groupcastaddr, sizeof(groupcastaddr)) < 0)
        {
            err_log("fail to bind");
        }
    
        struct ip_mreq req;
        req.imr_multiaddr.s_addr = inet_addr(argv[1]);
    //    req.imr_interface.s_addr = inet_addr("192.168.0.196");
        req.imr_interface.s_addr = htonl(INADDR_ANY);
    
        if(setsockopt(sockfd, IPPROTO_IP,IP_ADD_MEMBERSHIP, &req, sizeof(req)) < 0)
        {
            err_log("fail to setsockopt");
        }
    
        while(1)
        {
            if(recvfrom(sockfd, buf, N, 0, (struct sockaddr*)&clientaddr, &addrlen) < 0)
            {
                err_log("fail to recvfrom");
            }
    
            printf("From clientaddr:%s
    ", buf);
    
        }
    
        close(sockfd);
    
    
        
        return 0;
    }
  • 相关阅读:
    HTML Meta中添加X-UA-Compatible和IE=Edge,chrome=1有什么作用
    CSS+DIV定位分析(relative,absolute,static,fixed)
    Web中常用字体介绍
    CSS中强大的EM
    一线开发忙着实现,二线开发忙着变现
    Eclipse之父、《设计模式》作者、Junit作者之Erich Gamma
    著名软件工程师与作家、极限编程的创始者、JUnit作者之Kent Beck
    学习要构造反馈闭环
    技术人员也要全面发展
    2019第13周日
  • 原文地址:https://www.cnblogs.com/bwbfight/p/9304386.html
Copyright © 2011-2022 走看看