并发UDP服务器

服务器端代码如果采用fork写时复制(Copy on Write)技术,代码还可以更简洁一点

服务端代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUFSIZE 4096
#define CHILD_PORT_START 16500

const char* Inet_ntop(void* ptr) {
    static char str[INET_ADDRSTRLEN];
    return inet_ntop(AF_INET,ptr,str,INET_ADDRSTRLEN);
}

void server_echo(int sockfd) {
    int fullfd[2];
    if (socketpair(AF_UNIX,SOCK_DGRAM,0,fullfd) < 0) {
        printf("sockpair error: %s\n",strerror(errno));
        exit(1);
    }
    char recv[BUFSIZE];
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(struct sockaddr_in);
    ssize_t n;
    struct iovec iov[2];
    int pid;
    for (; ;) {
        if ((n = recvfrom(sockfd,recv,BUFSIZE,0,(struct sockaddr*)&clientaddr,&len)) < 0) {
            printf("receive from client error: %s\n",strerror(errno));
            break;
        }
        iov[0].iov_base = &clientaddr;
        iov[0].iov_len = len;
        iov[1].iov_base = recv;
        iov[1].iov_len = n;
        if (writev(fullfd[0],iov,2) != n + len) {
            printf("writev to child error: %s\n",strerror(errno));
            exit(1);
        }
        if ((pid = fork()) < 0) {
            printf("fork error: %s\n",strerror(errno));
            break;
        }else if (pid == 0) {
            struct sockaddr_in to;
            socklen_t tolen = sizeof(struct sockaddr_in);
            int childfd;
            struct sockaddr_in server;
            server.sin_family = AF_INET;
            server.sin_port = getpid() - getppid() + CHILD_PORT_START;
            server.sin_addr.s_addr = htonl(INADDR_ANY);
            struct iovec get[2];
            char send[BUFSIZE];
            ssize_t count = n;
            get[0].iov_base = &to;
            get[0].iov_len = sizeof(struct sockaddr_in);
            get[1].iov_base = send;
            get[1].iov_len = BUFSIZE;
            if (readv(fullfd[1],get,2) != count + tolen) {
                printf("readv error: %s\n",strerror(errno));
                exit(1);
            }
            printf("child process pid = %d handle from IP: %s client\n",getpid(),Inet_ntop(&to.sin_addr));
            if ((childfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0) {
                printf("child socket error: %s\n",strerror(errno));
            }
            if (bind(childfd,(struct sockaddr*)&server,sizeof(struct sockaddr_in)) < 0) {
                printf("child bind error: %s\n",strerror(errno));
                exit(1);
            }
            if (sendto(childfd,send,count,0,(struct sockaddr*)&to,tolen) != count) {
                printf("send to error: %s\n",strerror(errno));
                exit(1);
            }
            while ((count = recvfrom(childfd,send,BUFSIZE,0,(struct sockaddr*)&to,&tolen)) > 0) {
                if (sendto(childfd,send,count,0,(struct sockaddr*)&to,tolen) != count) {
                    printf("send to client error: %s\n",strerror(errno));
                    exit(1);
                }
            }
        }
    }
}
int main(int argc,char** argv) {
    if (argc != 2) {
        printf("please add or check <service name>\n");
        exit(1);
    }

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

    struct addrinfo* results;
    int err;
    if ((err = getaddrinfo(NULL,argv[1],&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;
        }
        if (ntohs(((struct sockaddr_in*)dummy->ai_addr)->sin_port) >= CHILD_PORT_START) {
            printf("Warnning:Dangerous use the port,if have many client,so you should use less than the port try once again\n");
            close(sockfd);
            exit(1);
        }
        if (bind(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) {
            break;
        }
        close(sockfd);
    }
    server_echo(sockfd);
    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);
        }
        struct sockaddr_in *dummy = (struct sockaddr_in*)to;
        dummy->sin_port = clientaddr.sin_port;
        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/79530372