UDP服务器绑定所有接口

服务端代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>

#define SERV_PORT 16002
#define BUFSIZE 4096

static void sig_child(int signo) {
    int pid;
    while ((pid = waitpid(-1,NULL,WNOHANG)) > 0) {
        printf("child process: %d terminated\n",pid);
    }
}
struct group_if {
    struct ifreq* gr_if;
    unsigned int gr_ifcount;
};

void* Malloc(size_t n) {
    void* ptr;
    if ((ptr = malloc(n)) == NULL) {
        printf("Malloc error: %s\n",strerror(errno));
        exit(1);
    }else {
        return ptr;
    }
}

void* Calloc(size_t n,size_t size) {
    void* ptr;
    if ((ptr = calloc(n,size)) == NULL) {
        printf("calloc error: %s\n",strerror(errno));
        exit(1);
    }else {
        return ptr;
    }
}

struct group_if get_group_if() {
    int sockfd;
    if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
        printf("group_if-get_if-error: %s\n",strerror(errno));
        exit(1);
    }
    char* buf;
    size_t lastlen = 0;
    size_t newlen = 10 * sizeof(struct ifreq);
    struct ifconf ifc;
    for (; ;) {
        buf = Malloc(newlen);
        ifc.ifc_len = newlen;
        ifc.ifc_buf = buf;
        if (ioctl(sockfd,SIOCGIFCONF,&ifc) < 0) {
            if (errno != EINVAL || lastlen != 0) {
                printf("ioctl error: %s\n",strerror(errno));
                exit(1);
            }
        }else {
            if (lastlen == ifc.ifc_len) {
                break;
            }
        }
        lastlen = ifc.ifc_len;
        newlen += 10 * sizeof(struct ifreq);
        free(buf);
    }
    struct group_if ret;
    size_t count = ifc.ifc_len / sizeof(struct ifreq);
    ret.gr_if = Calloc(count,sizeof(struct ifreq));
    memcpy(ret.gr_if,buf,ifc.ifc_len);
    free(buf);
    ret.gr_ifcount = count;
    return ret;
}
const char* Inet_ntop(void* ptr) {
    static char str[INET_ADDRSTRLEN];
    return inet_ntop(AF_INET,ptr,str,INET_ADDRSTRLEN);
}
void free_group_if(struct group_if grif) {
    if (grif.gr_if != NULL) {
        free(grif.gr_if);
    }
}
void server_echo(int sockfd) {
    char recv[BUFSIZE];
    ssize_t n;
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(struct sockaddr_in);
    for (; ;) {
        if ((n = recvfrom(sockfd,recv,BUFSIZE,0,(struct sockaddr*)&clientaddr,&len)) < 0) {
            printf("recvfrom error: %s\n",strerror(errno));
            exit(1);
        }
        printf("from IP: %s\n",Inet_ntop(&clientaddr.sin_addr));
        if (sendto(sockfd,recv,n,0,(struct sockaddr*)&clientaddr,len) != n) {
            printf("send to client error: %s\n",strerror(errno));
            exit(1);
        }
    }
}

int main(int argc,char ** argv) {
    int sockfd;
    const int on = 1;
    pid_t pid;
    struct group_if grif = get_group_if();
    struct sockaddr_in* sa,wild;
    struct ifreq* dummy = grif.gr_if;
    if (signal(SIGCHLD,sig_child) == SIG_ERR) {
        printf("signal error: %s\n",strerror(errno));
        exit(1);
    }
    for (size_t i = 1; i <= grif.gr_ifcount; ++i) {
        if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
            printf("main-socket error: %s\n",strerror(errno));
            exit(1);
        }
        if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
            printf("setsockopt error: %s\n",strerror(errno));
            exit(1);
        }
        if (ioctl(sockfd,SIOCGIFADDR,dummy) < 0) {
            printf("ioctl error: %s\n",strerror(errno));
            exit(1);
        }
        sa = (struct sockaddr_in*) &dummy->ifr_addr;
        sa->sin_family = AF_INET;
        sa->sin_port = htons(SERV_PORT);
        if (bind(sockfd,(struct sockaddr*)sa,sizeof(struct sockaddr_in)) < 0) {
            printf("bind error: %s\n",strerror(errno));
            exit(1);
        }
        printf("bound interface: %s ip-address: %s\n",dummy->ifr_name,Inet_ntop(&sa->sin_addr));
        if ((pid = fork()) < 0) {
            printf("fork error: %s\n",strerror(errno));
            exit(1);
        }else if (pid == 0){
            server_echo(sockfd);
            exit(0);
        }
        if (ioctl(sockfd,SIOCGIFFLAGS,dummy) < 0) {
            printf("ioctl-SIOCGIFFLAGS error: %s\n",strerror(errno));
            exit(1);
        }
        if (dummy->ifr_flags & IFF_BROADCAST) {
            if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
                printf("socket error: %s\n",strerror(errno));
                exit(1);
            }
            if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
                printf("setsockopt error: %s\n",strerror(errno));
                exit(1);
            }
            if (ioctl(sockfd,SIOCGIFBRDADDR,dummy) < 0) {
                printf("ioctl-SIOCGIFBRDADDR error: %s\n",strerror(errno));
                exit(1);
            }
            sa = (struct sockaddr_in*) &dummy->ifr_broadaddr;
            sa->sin_family = AF_INET;
            sa->sin_port = htons(SERV_PORT);
            if (bind(sockfd,(struct sockaddr*)sa,sizeof(struct sockaddr_in)) < 0) {
                if (errno == EADDRINUSE) {
                    printf("EADDRINUSE: %s\n",Inet_ntop(&sa->sin_addr));
                    close(sockfd);
                    continue;
                }else {
                    printf("bind error: %s\n",strerror(errno));
                    exit(1);
                }
            }
            printf("bound interface: %s broadcast-ip-address: %s\n",dummy->ifr_name,Inet_ntop(&sa->sin_addr));
            if ((pid = fork()) < 0) {
                printf("fork error: %s\n",strerror(errno));
                exit(1);
            }else if (pid == 0) {
                server_echo(sockfd);
                exit(0);
            }
        }
        dummy++;
    }
    free_group_if(grif);
    if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
        printf("sockfd error: %s\n",strerror(errno));
        exit(1);
    }
    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
        printf("setsockopt error: %s\n",strerror(errno));
        exit(1);
    }
    wild.sin_addr.s_addr = htonl(INADDR_ANY);
    wild.sin_family = AF_INET;
    wild.sin_port = htons(SERV_PORT);
    if (bind(sockfd,(struct sockaddr*)&wild,sizeof(struct sockaddr_in)) < 0) {
        printf("bind wild-address error: %s\n",strerror(errno));
        exit(1);
    }
    printf("bound wild-address %s\n",Inet_ntop(&wild.sin_addr));
    if ((pid = fork()) < 0) {
        printf("fork error: %s\n",strerror(errno));
        exit(1);
    }else if (pid == 0) {
        server_echo(sockfd);
        exit(0);
    }else {
        for (; ;) {
        }
    }
    return 0;
}

客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>

#define BUFSIZE 4096

void client_echo(int sockfd,struct sockaddr* to,socklen_t tolen) {
    char send[BUFSIZE];
    ssize_t n;
    struct sockaddr_in clientaddr;
    const int on = 1;
    socklen_t len = sizeof(struct sockaddr_in);
    if (setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)) < 0) {
        printf("setsockopt error: %s\n",strerror(errno));
        exit(1);
    }
    while ((n = read(STDIN_FILENO,send,BUFSIZE)) > 0) {
        if (sendto(sockfd,send,n,0,to,tolen) != n) {
            printf("sendto error: %s\n",strerror(errno));
            exit(1);
        }
        if (recvfrom(sockfd,send,BUFSIZE,0,(struct sockaddr*)&clientaddr,&len) != n) {
            printf("recv from server error: %s\n",strerror(errno));
            exit(1);
        }
        if (write(STDOUT_FILENO,send,n) != n) {
            printf("write error: %s\n",strerror(errno));
            exit(1);
        }
    }
}
int main(int argc,char** argv) {
    if (argc != 3) {
        printf("please add <ip address-host name> <service name or port name>\n");
        exit(1);
    }

    struct addrinfo hints;
    bzero(&hints,sizeof(struct addrinfo));
    hints.ai_flags = AI_ALL;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;

    struct addrinfo* results;
    int err;
    if ((err = getaddrinfo(argv[1],argv[2],&hints,&results)) != 0) {
        printf("getaddrinfo error: %s\n",gai_strerror(err));
        exit(1);
    }

    struct addrinfo* dummy = results;
    int sockfd;
    for (; dummy != NULL; dummy = dummy->ai_next) {
        if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) {
            continue;
        }else {
            break;
        }
    }

    if (dummy == NULL) {
        freeaddrinfo(results);
        printf("all socket failed\n");
        exit(1);
    }
    client_echo(sockfd,dummy->ai_addr,dummy->ai_addrlen);
    freeaddrinfo(results);
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/rgbmarco/article/details/79525918