Unix/Linux守護程式伺服器示例

RGBMarco發表於2018-02-13

服務端程式碼:

#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/wait.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MAXFD 100
#define LISTENQ 100
#define BUFSIZE 4096
void sig_child(int signo) {
    int ppid;
    while ((ppid = waitpid(-1,NULL,WNOHANG)) > 0) {
        syslog(LOG_NOTICE,"child process number: %d terminated",ppid);
    }
}

void server_echo(int fd) {
    char buf[BUFSIZE];
    int n;
    time_t t = time(NULL);
    strftime(buf,BUFSIZE,"%Y %x %X",localtime(&t));
    int len = strlen(buf);
    buf[len - 1] = '\n';
    buf[len] = '\0';
    if (write(fd,buf,strlen(buf)) != strlen(buf)) {
        syslog(LOG_ERR,"pid: %d write error: %s\n",getpid(),strerror(errno));
        exit(1);
    }
}
int main(int argc,char **argv) {
    if (argc != 2) {
        printf("please add <service name or port\n");
        exit(1);
    }

    int pid;
    if ((pid = fork()) < 0) {
        printf("fork error: %s\n",strerror(errno));
        exit(1);
    }else if (pid) {
        exit(0);
    }

    if (setsid() < 0) {
        printf("setsid error: %s\n",strerror(errno));
        exit(1);
    }

    if (signal(SIGHUP,SIG_IGN) == SIG_ERR) {
        syslog(LOG_ERR,"pid: %d fork error: %s\n",getpid(),strerror(errno));
        exit(1);
    }
    umask(0);
    if ((pid = fork()) < 0) {
        syslog(LOG_ERR,"pid: %d fork error: %s\n",getpid(),strerror(errno));
        exit(1);
    }else if (pid) {
        exit(0);
    }

    chdir("/");
    for (int i = 0; i < MAXFD; ++i) {
        close(i);
    }
    open("/dev/null",O_RDONLY);
    open("/dev/null",O_RDWR);
    open("/dev/null",O_RDWR);

    struct addrinfo hints;
    bzero(&hints,sizeof(struct addrinfo));

    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    struct addrinfo* results;
    int err;
    if ((err = getaddrinfo(NULL,argv[1],&hints,&results)) != 0) {
        syslog(LOG_ERR,"pid: %d getaddrinfo error: %s\n",getpid(),gai_strerror(err));
        exit(1);
    }
    int sockfd;
    struct addrinfo* dummy = results;
    for (; dummy != NULL; dummy = dummy->ai_next) {
        if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) {
            continue;
        }

        if (bind(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) {
            break;
        }

        close(sockfd);
    }
    if (dummy == NULL) {
        freeaddrinfo(results);
        syslog(LOG_NOTICE,"pid: %d all connect failed\n",getpid());
        exit(1);
    }
    freeaddrinfo(results);
    if (listen(sockfd,LISTENQ) < 0) {
        syslog(LOG_ERR,"pid: %d listen error: %s\n",getpid(),strerror(errno));
        exit(1);
    }
    if (signal(SIGCHLD,sig_child) == SIG_ERR) {
        syslog(LOG_ERR,"pid: %d signal error: %s\n",getpid(),strerror(errno));
        exit(1);
    }
    int connfd;
    for (; ;) {
        errno = 0;
        if ((connfd = accept(sockfd,NULL,NULL)) < 0) {
            if (errno == EINTR) {
                continue;
            }
            syslog(LOG_ERR,"pid:%d accept error: %s\n",getpid(),strerror(errno));
            exit(1); 
        }
        if ((pid = fork()) < 0) {
            syslog(LOG_ERR,"pid:%d fork error: %s\n",getpid(),strerror(errno));
            exit(1);
        }else if (pid == 0) {
            close(sockfd);
            server_echo(connfd);
            close(connfd);
            exit(0);
        }
        close(connfd);
    }
    return 0;
}

客戶端程式碼:

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

#define BUFSIZE 4096

int main(int argc,char **argv) {
    if (argc != 3) {
        printf("please add <ip address or host name> <service name or port>\n");
        exit(1);
    }

    struct addrinfo hints;
    bzero(&hints,sizeof(struct addrinfo));

    hints.ai_flags = AI_ALL;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    struct addrinfo* results;
    int err;

    if ((err = getaddrinfo(argv[1],argv[2],&hints,&results)) != 0) {
        printf("getaddrinfor 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 (connect(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) {
            break;
        }
        close(sockfd);
    }

    char recv[BUFSIZE];
    int n;

    while ((n = read(sockfd,recv,BUFSIZE)) > 0) {
        if (write(STDOUT_FILENO,recv,n) != n) {
            printf("write error: %s\n",strerror(errno));
            exit(1);
        }
    }
    return 0;
}

相關文章