• 【linux高级程序设计】(第十五章)UDP网络编程应用 3


    UDP组播通信

    组播IP地址: D类IP地址  1110.**********  224.0.0.1 ~ 239.255.255.255

    组播MAC地址:低23位,直接对应IP地址, 从右数第24位为0, 前24位为 01:00:5E

    最终数据帧如图

    局域网所有主机网卡都会收到这一消息,但是只有加入到组内的主机才接受该数据包。组播不影响同一局域网内其他主机的效率

    将自己的主机IP地址加入到组播地址组:

    setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq));

    第四个参数的类型如下:

    struct ip_mreqn
    {
        struct in_addr imr_multiaddr;   //组播地址
        struct in_addr imr_address;     //自己IP地址
    };

    加入相应的组后,即可接收对应组播地址的数据包了

    例子:

    发送端:发送组播消息 绑定了自己的ip  没有加入组 只是说发送到某个组

    接收端:加入了正确的组,则可以接收到;没有加入相应的组,则不能接收到

    用到了新的函数

    gethostbyname

    #include<netdb.h>
    struct hostent* gethostbyname(const char* hostname);

    返回值类型

    struct hostent{
      char * h_name;
      char ** h_aliases;
      short h_addrtype;
      short h_length;
      char ** h_addr_list;
    };
    #define h_addr h_addr_list[0]

    bcopy

     void bcopy(const void *src, void *dest, int n);

    发送端代码:

    #include<sys/types.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define BUFLEN 255
    
    int main(int argc, char **argv)
    {
        struct sockaddr_in peeraddr, myaddr;
        int sockfd;
        char recmsg[BUFLEN + 1];
        unsigned int socklen;
        //以UDP方式创建SOCKET对象
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0)
        {
            printf("socket creating error
    ");
            exit(EXIT_FAILURE);
        }
        socklen = sizeof(struct sockaddr_in);
        memset(&peeraddr, 0, socklen);
        peeraddr.sin_family = AF_INET;
        peeraddr.sin_port = htons(7838); 
        if(argv[1])      //参数1 获取组播地址
        {
            if(inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0)
            {
                printf("wrong group address!
    ");
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            printf("no group address!
    ");
            exit(EXIT_FAILURE);
        }
        memset(&myaddr, 0, socklen);
        myaddr.sin_family = AF_INET;
        myaddr.sin_port = htons(23456);
        if(argv[2])    //参数2  读取本机绑定的IP地址
        {
            if(inet_pton(AF_INET, argv[2], &myaddr.sin_addr) <= 0)
            {
                printf("self ip address error!
    ");
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            myaddr.sin_addr.s_addr = INADDR_ANY;
        }
        //绑定
        if(bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) == -1)
        {
            printf("Bind error
    ");
            exit(EXIT_FAILURE);
        }
        while(1)
        {
            bzero(recmsg, BUFLEN + 1);
            printf("input message to send:");
            if(fgets(recmsg, BUFLEN, stdin) == (char *)EOF)
                exit(EXIT_FAILURE);
            //发送给组播组内主机
            if(sendto(sockfd, recmsg, strlen(recmsg), 0, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) < 0)
            {
                printf("sendto error
    ");
                exit(EXIT_FAILURE);
            }
            printf("send message:%s
    ", recmsg);
        }
    }

    接收端代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/types.h>
    #include<netinet/in.h>
    #include<netinet/tcp.h>
    #include<sys/socket.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<arpa/inet.h>
    #include<sys/time.h>
    #include<netdb.h>
    #define BUFLEN 255
    
    int main(int argc, char **argv)
    {
        struct sockaddr_in peeraddr;
        struct in_addr ia;
        int sockfd;
        char recmsg[BUFLEN + 1];
        unsigned int socklen, n;
        struct hostent *group;
        struct ip_mreq mreq;
        //创建socket UDP
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);  //创建UDP方式的socket
        if(sockfd < 0)
        {
            perror("socket");
            exit(EXIT_FAILURE);
        }
        bzero(&mreq, sizeof(struct ip_mreq));
        //从参数1获取组播地址
        if(argv[1])
        {
            if((group = gethostbyname(argv[1])) == (struct hostent *)0)  //??
            {
                perror("gethostbyname");
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            printf("please input a group address: 224.0.0.1 ~ 239.255.255.255
    ");
            exit(EXIT_FAILURE);
        }
        bcopy((void *)group->h_addr, (void *)&ia, group->h_length);  //??
        bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr)); //??
        //从参数2中读取本机IP地址
        if(argv[2])
        {
            if(inet_pton(AF_INET, argv[2], &mreq.imr_interface.s_addr) <= 0)
            {
                printf("Wrong dest IP address!
    ");
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            printf("Wrong dest IP address!
    ");
            exit(EXIT_FAILURE);
        }
        
        //设置客户端加入到组
        if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1)
        {
            perror("setsockopt");
            exit(EXIT_FAILURE);
        }
        //
        socklen = sizeof(struct sockaddr_in);
        memset(&peeraddr, 0, socklen);
        peeraddr.sin_family = AF_INET;
        peeraddr.sin_port = htons(7838); 
        if(argv[1])      //参数1 获取组播地址
        {
            if(inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0)
            {
                printf("wrong group address!
    ");
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            printf("no group address!
    ");
            exit(EXIT_FAILURE);
        }
        //绑定
        if(bind(sockfd, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) == -1)
        {
            printf("Bind error
    ");
            exit(EXIT_FAILURE);
        }
        while(1)
        {
            bzero(recmsg, BUFLEN + 1);
            n = recvfrom(sockfd, recmsg, BUFLEN, 0, (struct sockaddr *)&peeraddr, &socklen);
            if(n < 0)
            {
                printf("recvfrom err in udptalk!
    ");
                exit(EXIT_FAILURE);
            }
            else
            {
                recmsg[n] = 0;
                printf("peer:%s
    ", recmsg);
            }
        }
    }

  • 相关阅读:
    这仅仅是一份工作
    和老总之间的对话
    假设满足怎样的条件,就不去编程
    那都是别人的架构
    程序员狂想曲
    学点经济学知识(三)
    一起来看 HTML 5.2 中新的原生元素 <dialog>
    动态配置页面 之 组件系统
    初识JavaScript EventLoop
    webpack+vue-cli+ElementUI+vue-resource 前端开发
  • 原文地址:https://www.cnblogs.com/dplearning/p/4708149.html
Copyright © 2020-2023  润新知