• udp组播的实现


    组播在内核里面对应的一个重要的结构体是ip_mreq,如下:

    struct ip_mreq 
    {
        struct in_addr imr_multiaddr;    /* IP multicast address of group */
        struct in_addr imr_interface;    /* local IP address of interface */
    };
    View Code

    而一台服务器上可能有多个网卡,系统要允许用户使用其中的某个网卡加入某一个主机组,imr_interface参数就是指定一个特定的设备接口,
    告诉协议栈只想在这个设备所在的子网中加入某个组播组。有了这两个参数,协议栈就能知道:在哪个网络设备接口上加入哪个组播组。

    下面是一个组播的例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <netdb.h>
    #include <errno.h>
    
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <linux/if.h>
    #include <linux/route.h>
    #include <netinet/ether.h>
    #include <netpacket/packet.h>
    #include "server.h"
    
    bool mySystem(const char *command)
    {
        int status;
        status = system(command);  
      
        if (-1 == status)  
        {  
            printf("mySystem: system error!");  
            return false;
        }  
        else  
        {  
            if (WIFEXITED(status))  
            {  
                if (0 == WEXITSTATUS(status))  
                {  
                    return true; 
                }               
                printf("mySystem: run shell script fail, script exit code: %d
    ", WEXITSTATUS(status));  
                return false;   
            }    
            printf("mySystem: exit status = [%d]
    ", WEXITSTATUS(status));   
            return false;
        }  
    }
        
    
    void fillRspHead(char *buff, char type)
    {
        if (type == 'g')
        {
            memcpy(buff, "getmac|", 7);
        }
        else if (type == 's')
        {
            memcpy(buff, "setip|", 6);
        }
        else
        {
            printf("fillRspHead: invalid command type!
    ");
            return;
        }
    }
    void fillSN(char *buff)
    {
        FILE *fp;
        int bufflen = strlen(buff);
        if((fp=fopen(SN_FILE, "r")) == NULL)
        {   
            strcat(buff, "|");
            perror("getSN: fopen");
            return;
        }
        fgets(buff + bufflen, NETLEN, fp);
        while(buff[strlen(buff) - 1] == '
    ' || buff[strlen(buff) - 1] == ' ')
        {
            buff[strlen(buff) - 1] = '';
        }
        strcat(buff, "|");
        fclose(fp);
    }
    
    void fillType(char *buff)
    { 
        strcat(buff, HOST_TYPE);
        strcat(buff, "|");
    }
    
    void fillNetworkInfo(char *buff)
    {
        
        unsigned char netbuff[NETLEN];
        unsigned char temp[NETLEN];
        int socketfd;
        FILE *gatewayfd;
        struct ifreq struReq;
        memset(&struReq, 0, sizeof(struct ifreq));
        memset(netbuff, 0, sizeof(netbuff));
        strncpy(struReq.ifr_name, "eth0", sizeof(struReq.ifr_name));
    
        socketfd = socket(PF_INET, SOCK_STREAM, 0);
    
        if (-1 == ioctl(socketfd, SIOCGIFHWADDR, &struReq))
        {
            perror("ioctl hwaddr error!
    ");
            strcat(buff, "|");
            goto fillip;
        }
        strcpy((char *)netbuff, ether_ntoa((struct ether_addr*)struReq.ifr_hwaddr.sa_data));
        strcat(buff, netbuff);
        strcat(buff, "|");
    fillip:
        if (-1 == ioctl(socketfd, SIOCGIFADDR, &struReq))
        {
            perror("ioctl ip address error!
    ");
            strcat(buff, "|");
            goto fillnetmask;
        }
        strcpy((char *)netbuff, inet_ntoa(((struct sockaddr_in *)&(struReq.ifr_addr))->sin_addr));
        strcat(buff, netbuff);
        strcat(buff, "|");
    fillnetmask:    
        if (-1 == ioctl(socketfd, SIOCGIFNETMASK, &struReq))
        {
            perror("ioctl net mask error!
    ");
            strcat(buff, "|");
            goto fillgateway;
        }
        strcpy((char *)netbuff, inet_ntoa(((struct sockaddr_in *)&(struReq.ifr_netmask))->sin_addr));
        strcat(buff, netbuff);
        strcat(buff, "|");
    fillgateway:    
        if(gatewayfd = popen("route -n | grep 'UG'", "r"))
        {
                fread(temp, 1, NETLEN, gatewayfd);
                sscanf(temp, "%*s%s", netbuff);
                strcat(buff, netbuff);
        }
        else
        {
            perror("fillNetworkInfo: popen!");
            strcat(buff, "|");
        }
    
        pclose(gatewayfd);
        close(socketfd);
      
        return;     
    }
    
    bool matchMAC(char *buff)
    {
        unsigned char reqmac[NETLEN];
        unsigned char mymac[NETLEN];
    
        unsigned char *start;
        int socketfd;
        struct ifreq struReq;
        memset(reqmac, 0, sizeof(reqmac));
        memset(mymac, 0, sizeof(mymac));
        memset(&struReq, 0, sizeof(struct ifreq));
        strncpy(struReq.ifr_name, "eth0", sizeof(struReq.ifr_name));
        
        socketfd = socket(PF_INET, SOCK_STREAM, 0);
    
        if (-1 == ioctl(socketfd, SIOCGIFHWADDR, &struReq))
        {
            perror("ioctl hwaddr error!
    ");
            return false;
        }
        strcpy((char *)mymac, ether_ntoa((struct ether_addr*)struReq.ifr_hwaddr.sa_data));
        if ((start = strchr(buff, '|')) == NULL) 
        {
            printf("matchMAC: invalid msg format from rackman!
    ");
            return false;
        }
        printf("mac in req =%s, mac myself =%s
    ", start+1, mymac);
        if (strncmp(mymac, start + 1, strlen(mymac)) == 0)
        {
    #ifdef DEBUG
            printf("mac matched!
    ");
    #endif
            return true;
        }
    #ifdef DEBUG
        printf("mac not matched!
    ");
    #endif
        return false;
    }
    
    void splitReq(char *buff, char save[][NETLEN])
    {
        char *p;    
        int i = 0;
        p = strtok(buff, "|");   
        while(i < REQ_PART_NUM)      
        {   
            if (!p)
            {
                printf("splitReq:the %drd part info is empty!
    ", i+1);
            }
            else
            {
    #ifdef DEBUG
                printf("%s
    ", p);   
    #endif
                strcpy(save[i], p);
            }
            p = strtok(NULL, "|");  
            i++;
        }      
    }
    
    bool setNetwork(const char *ipaddr, const char *netmask, const char *gateway)
    {
        struct ifreq ifr;  
        struct sockaddr_in saddr;  
        struct rtentry rte;  
        struct sockaddr_in rtdst;  
        struct sockaddr_in rtgw;  
        if (NULL == ipaddr || NULL == netmask || NULL == gateway)
        {
            printf("writeConfig: invalid network parameters!
    ");
            return false;
        }
        int fd = socket(AF_INET, SOCK_DGRAM, 0);  
        if (fd == -1) 
        {  
          printf("setInterface: Failed to create socket: %s", strerror(errno));  
          return false;  
        }  
     
        memset(&ifr, 0, sizeof(ifr));  
        strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);  
    
        memset(&saddr, 0, sizeof(saddr));  
        saddr.sin_family = AF_INET;  
        inet_aton(ipaddr, &saddr.sin_addr);  
        memcpy(&ifr.ifr_addr, &saddr, sizeof(saddr));  
    
        if (ioctl(fd, SIOCSIFADDR, &ifr) == -1) 
        {  
            printf("setInterface: Failed to set interface address %s: %s", ipaddr, strerror(errno));  
            close(fd);
            return false;  
        }  
    
        inet_aton(netmask,  &(((struct sockaddr_in*)&(ifr.ifr_netmask))->sin_addr));    
        if (ioctl(fd, SIOCSIFNETMASK, &ifr) == -1) 
        {  
            printf("setInterface: Failed to set interface netmask %s: %s", netmask, strerror(errno));  
            close(fd);
            return false;  
        }  
    
        memset(&rte, 0, sizeof(rte));  
        rte.rt_flags = RTF_UP | RTF_GATEWAY;  
        memset(&rtdst, 0, sizeof(rtdst));  
        rtdst.sin_family = AF_INET;  
        memcpy(&rte.rt_dst, &rtdst, sizeof(rtdst));  
        ioctl(fd, SIOCDELRT, &rte);
    
        memset(&rtgw, 0, sizeof(rtgw));  
        rtgw.sin_family = AF_INET;  
        inet_aton(gateway, &rtgw.sin_addr);  
        memcpy(&rte.rt_gateway, &rtgw, sizeof(rtgw));  
        if (ioctl(fd, SIOCADDRT, &rte) == -1) 
        {  
            printf("setInterface: Failed to add gateway %s: %s", gateway, strerror(errno));
            close(fd);
            return false;
        }  
    
        close(fd);  
        return true;
    }
    
    bool writeConfig(const char *ipaddr, const char *netmask, const char *gateway)
    {
        char wbuff[BUFLEN];
    #ifdef MCPU
        FILE *fp;
        char rbuff[BUFLEN];
        if (NULL == ipaddr || NULL == netmask || NULL == gateway)
        {
            printf("writeConfig: invalid network parameters!
    ");
            return false;
        }
        if((fp=fopen(SYS_NETWORK_FILE, "r+")) == NULL)
        {    
            perror("writeConfig: fopen error!");
            return false;
        }
        while (!feof(fp)) 
        {
            fgets(rbuff, BUFLEN, fp);
            if (rbuff[0] == '#')
            {
                continue;
            }
            if (strncmp(rbuff, "iface eth0", 10) == 0)
            {
                sprintf(wbuff, "address %s
    ", ipaddr);
                fputs(wbuff, fp);
                sprintf(wbuff, "netmask %s
    ", netmask);
                fputs(wbuff, fp);
                sprintf(wbuff, "gateway %s
    ", gateway);
                fputs(wbuff, fp);
                sprintf(wbuff, "route add default gw %s dev eth0
    ", gateway);
                fputs(wbuff, fp);
                fclose(fp);
                return true;
            } 
        }
        sprintf(wbuff, "echo auto eth0 >> %s", SYS_NETWORK_FILE);
        mySystem(wbuff);
        sprintf(wbuff, "echo iface eth0 inet static >> %s", SYS_NETWORK_FILE);
        mySystem(wbuff);
        sprintf(wbuff, "echo address %s >> %s", ipaddr, SYS_NETWORK_FILE);
        mySystem(wbuff);
        sprintf(wbuff, "echo netmask %s >> %s", netmask, SYS_NETWORK_FILE);
        mySystem(wbuff);
        sprintf(wbuff, "echo gateway %s >> %s", gateway, SYS_NETWORK_FILE);
        mySystem(wbuff);
        sprintf(wbuff, "route add default gw %s dev eth0 >> %s", gateway, SYS_NETWORK_FILE);
        mySystem(wbuff);
        return true;
    #else
        sprintf(wbuff, "sed -i "/IPADDR/s/=.*/=%s/" %s", ipaddr, SYS_NETWORK_FILE);
        mySystem(wbuff);
        sprintf(wbuff, "sed -i "/NETMASK/s/=.*/=%s/" %s", netmask, SYS_NETWORK_FILE);
        mySystem(wbuff);
        sprintf(wbuff, "sed -i "/GATEWAY/s/=.*/=%s/" %s", gateway, SYS_NETWORK_FILE);
        mySystem(wbuff);
        return true;
    #endif
    }
    void sendRsp(int sockfd, struct sockaddr_in *clntaddr, char *rsp)
    {
        if (sendto(sockfd, rsp, strlen(rsp), 0, (struct sockaddr *) clntaddr, sizeof(struct sockaddr_in)) < 0) 
        {
            perror("sendRsp: sendto!");
            return;
        }
    #ifdef DEBUG
        printf("send msg to client ok: %s
    ", rsp);
    #endif
    }
    
    bool addHostGroup(int recvfd)
    {
        struct hostent *group;
        struct ip_mreq mreq;
        struct in_addr ia;
        bzero(&mreq, sizeof(struct ip_mreq));
        
        if ((group = gethostbyname(MULTI_CAST_ADDR)) == (struct hostent *) 0) 
        {
            perror("gethostbyname"); 
            return false;
        }
    
        bcopy((void *) group->h_addr, (void *) &ia, group->h_length);
    
        bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr));
    
    
        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    
    
        if (setsockopt(recvfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1) 
        {
            perror("addHostGroup: setsockopt!"); 
            return false;
        }
        return true;
    }
    
    bool bindSocket(int recvfd, int sendfd)
    {
        struct sockaddr_in recvaddr, sendaddr;
        int socklen = sizeof(struct sockaddr_in);
        
        memset(&recvaddr, 0, socklen);
        memset(&sendaddr, 0, socklen);
        recvaddr.sin_family = AF_INET;
        recvaddr.sin_port = htons(MULTI_CAST_PORT);   
        if (inet_pton(AF_INET, MULTI_CAST_ADDR, &recvaddr.sin_addr) <= 0) 
        {
            perror("bindSocket: inet_pton error!");
            return false;
        }
    
        if (bind(recvfd, (struct sockaddr *) &recvaddr, socklen) == -1) 
        {
            perror("bindSocket: bind recvfd error!");
            return false;
        }
    
        sendaddr.sin_family = AF_INET;
        sendaddr.sin_port = htons(RACKMAN_LISTEN_PORT);   
        sendaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    
        if (bind(sendfd, (struct sockaddr *) &sendaddr, socklen) == -1) 
        {
            perror("bindSocket: bind sendfd error!");
            return false;
        }
        
        return true;
    }
    
    int main(int argc, char **argv)
    {
        struct sockaddr_in clntaddr;
        
        int recvfd, sendfd;
        char recmsg[BUFLEN + 1];
        char rspmsg[BUFLEN + 1];
        char netinfo[REQ_PART_NUM][NETLEN];
        unsigned int socklen, n;
        char *addr;
        bool ret;
        
        //create socket
        recvfd = socket(AF_INET, SOCK_DGRAM, 0);
        sendfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (recvfd < 0 || sendfd < 0) 
        {
            printf("socket creating err in udptalk
    ");
            return -1;
        }
        if (addHostGroup(recvfd) == false)
        {
            printf("server: addHostGroup error!
    ");
            close(recvfd);
            close(sendfd);
            return -1;
        }
        if (bindSocket(recvfd, sendfd) == false)
        {
            printf("server: bindSocket error!
    ");
            close(recvfd);
            close(sendfd);
            return -1;
        }
        
        while(1)
        {
            bzero(recmsg, BUFLEN + 1);
            bzero(rspmsg, BUFLEN + 1);
            socklen = sizeof(struct sockaddr_in);
            n = recvfrom(recvfd, recmsg, BUFLEN, 0, (struct sockaddr *) &clntaddr, &socklen);
            if (n < 0) 
            {
                perror("Rackman server: recvfrom error!");
                continue;
            } 
    //receive msg from rackman client
            recmsg[n] = 0;
    #ifdef DEBUG 
            addr = (char *)inet_ntoa(clntaddr.sin_addr);           
            printf("client address = %s, port = %d
    ", addr, ntohs(clntaddr.sin_port));
            printf("receive msg from client: %s
    ", recmsg);
    #endif
            clntaddr.sin_port = htons(RACKMAN_LISTEN_PORT);
            if (inet_pton(AF_INET, RACKMAN_MULTI_CAST_ADDR, &clntaddr.sin_addr) <= 0) 
            {
                perror("inet_pton: inet_pton error!");
                return -1;
            }
            fillRspHead(rspmsg, recmsg[0]);
            if (strncmp(recmsg, "setip", 5) == 0)
            {
                if (matchMAC(recmsg))
                {                
                    splitReq(recmsg, netinfo);
    #ifdef DEBUG                
                    printf("setip: ip = %s, netmask = %s, gateway = %s
    ", netinfo[2], netinfo[3], netinfo[4]);
    #endif
                    ret = setNetwork((const char *)netinfo[2], (const char *)netinfo[3], (const char *)netinfo[4]);
                    if (ret == true)
                    {
                        strcat(rspmsg, "success|");
                        writeConfig((const char *)netinfo[2], (const char *)netinfo[3], (const char *)netinfo[4]);
                    }
                    else
                    {
                        strcat(rspmsg, "failed|");
                    }
                }
                else 
                {
                    continue;
                }
            }
            fillSN(rspmsg);
            fillType(rspmsg);
            fillNetworkInfo(rspmsg);
            sendRsp(sendfd, &clntaddr, rspmsg);                
        }
    }
    View Code

    .h文件:

    #ifndef MULTICAST_SERVER_H
    #define MULTICAST_SERVER_H
    
    #define MULTI_CAST_ADDR     "234.5.6.7"
    #define MULTI_CAST_PORT     (4567)
    #define RACKMAN_MULTI_CAST_ADDR "234.5.6.8"
    #define RACKMAN_LISTEN_PORT (4568)
    #define BUFLEN              300
    #define NETLEN              100
    #define REQ_PART_NUM        5
    
    #ifdef MCPU
    #define SN_FILE             "/MCPUSN"
    #define HOST_TYPE           "mcpu"
    #define SYS_NETWORK_FILE    "/etc/network/interfaces"
    #else
    #define SN_FILE             "/nandflash/chassisSN"
    #define HOST_TYPE           "bmc" 
    #define SYS_NETWORK_FILE    "/nandflash/network"
    
    #endif
    
    typedef enum
    {
        false,
        true
    }bool;
    #endif
    View Code
  • 相关阅读:
    Django restframework api版本控制组件增加及源码分析
    Django restframework用户访问频率控制组件增加及源码分析
    Django restframework用户权限认证组件增加及源码分析
    Django restframework用户登录认证组件增加及源码分析
    Django restframework视图访问流程源码剖析
    01 二维数组中的查找
    Linux基础
    函数设计原则
    递归函数分析
    函数与宏分析
  • 原文地址:https://www.cnblogs.com/chaozhu/p/5713740.html
Copyright © 2020-2023  润新知