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
原文地址:https://www.cnblogs.com/chaozhu/p/5713740.html