一个简单的网络服务端demo示例

/*linux socket server demo
*
*date:2016-2-10
*
*author:xiehaocheng
*
*/
#include<sys/types.h>   /* basic system data types */
#include<sys/socket.h>  /* basic socket definitions */
#include<arpa/inet.h>   /* inet(3) functions */
#include<netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<errno.h>
#include<stdarg.h>
#include<string.h>
#include<syslog.h>


typedef void (*SIG_FUNC)(int);
/* 
 * This function is to print debug message and 'errno'
 */
void err_exit(const char *msg, ...)
{
    char buf[512];
    va_list args;
    va_start(args, msg);
    vsprintf(buf, msg, args);
    sprintf(buf+strlen(buf), ":%s", strerror(errno)); 
    strcat(buf, "\n");
    va_end(args);
    printf("%s", (char *)buf);
    fflush(stdout);     /* fflush std buffer */ 
    exit(1);
}

void sigpipe_handler(int sig)
{
    printf("Get signal PIPE!\n");
}
/*
* Handler of SIGCHLD 
* use waitpid to set wait noblock
*/
void sig_chld_handler(int signo)
{
    pid_t pid;
    int stat;
    while((pid = waitpid(-1, &stat, WNOHANG)) > 0) /*waitpid is noblock*/
        printf("child process terminated!--child pid = %d!\n",pid);
    return;
}
/*
 * Set signal handler for SIGCHLD,to wait child process,clean zombies
*/
int set_signal(int signo, SIG_FUNC func)
{
    struct sigaction act, oact;
    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (signo == SIGALRM) {
#ifdef  SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;       /* SunOS 4.x */
#endif
    } else {        //Only SIGALRM can interrupt the system call, otherwise we restart system call 
#ifdef  SA_RESTART
        act.sa_flags |= SA_RESTART;     /* SVR4, 44BSD */
#endif
    }
    if (sigaction(signo, &act, &oact) < 0)
        return(-1);
    return 0;
}

void server_function(int fd)
{
    /*handle I/O timeout*/
    struct timeval tv;
    tv.tv_sec = 10;
    tv.tv_usec = 0;

    if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ||
        setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
    {
        printf("failed to setsockopt!\n");
        exit(1);
    }

    /*handle with the connect fd
    here just print something for test*/
    printf("the connect fd is %d\n",fd);
    printf("sleep 1 second and exit\n");
    sleep(1);
    close(fd);
    /*************************/
}
ssize_t             /* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)
{
    size_t  nleft;
    ssize_t nread;
    char    *ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) {
        if ( (nread = read(fd, ptr, nleft)) < 0) {
            if (errno == EINTR)
                nread = 0;/* and call read() again */
            else
                return(-1);
        } else if (nread == 0)
            break;      /* EOF */

        nleft -= nread;
        ptr   += nread;
    }
    return(n - nleft);          /* return >= 0 */
}
ssize_t                     /* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
    size_t      nleft;
    ssize_t     nwritten;
    const char  *ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) {
        if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
            if (nwritten < 0 && errno == EINTR)
                nwritten = 0;   /* and call write() again */
            else
                return(-1); /* error */
        }

        nleft -= nwritten;
        ptr   += nwritten;
    }
    return(n);
}
/* The main function 
*/
int main(int argc, char *argv[])
{
    printf("enter server\n");
    int listen_fd, connect_fd, value = 1;
    pid_t pid;
    struct sockaddr_in server_addr, client_addr;


    if(set_signal(SIGCHLD, sig_chld_handler) == -1){ //Set signal handler to handle SIGCHLD
        err_exit("signal SIGCHLD set error");
    }

    if (set_signal(SIGPIPE, sigpipe_handler) == -1){
        err_exit("signal SIGPIPE set error!\n");
    }

    if((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        err_exit("new socket error"); //This function will ends exit 
    }

    if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, 
            (const void *)&value, sizeof(value))){
        printf("setsockopt address reuseable error!\n");
    }   

    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(3333);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if(bind(listen_fd, (struct sockaddr *)&server_addr, 
                sizeof(struct sockaddr)) == -1){
        err_exit("socket bind error");
    }

    if(listen(listen_fd, 10) == -1){
        err_exit("listen error"); 
    }

    for(;;){
        int clilen = sizeof(struct sockaddr_in);
        printf("accept... \n");
        if ((connect_fd = accept(listen_fd, (struct sockaddr *)&client_addr, 
                            (socklen_t *)&clilen)) == -1){
            if (errno == EINTR){
                printf("interrupt by signal!\n");
            } else if (errno == ECONNABORTED){
                printf("ECONNABORTED\n");
            } else {
                printf("accept system call error!\n");
                exit(1);
            }
            continue;
        }
        printf("server received a connection from %s \n", inet_ntoa(client_addr.sin_addr));

        if ((pid = fork()) < 0){
            err_exit("fork() error");
            exit(1);
        } else if (pid == 0){   /* child process */
            close(listen_fd);  
            server_function(connect_fd);
            exit(0);
        }       
        close(connect_fd);  /* parent closes connected socket */
    }
}

猜你喜欢

转载自blog.csdn.net/rikeyone/article/details/80973933