TCP 回射程序(同步處理僵死進程的方式)

參考:http://www.cnblogs.com/Anker/p/3271773.html

客戶端的代碼:

/*************************************************************************
    > File Name: tcpcli.c
    > Author: mhsheng
    > Mail:[email protected] 
    > Created Time: Wed 09 Nov 2016 10:55:40 AM CST
 ************************************************************************/

// c standard head file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>

// system i/o head file
#include <unistd.h>

// socket head file
#include <netinet/in.h>

#define MAXLINE     1024
#define LISTENQ     5
#define SERV_PORT   9066    

void
err_quit(const char *str_err)
{
    fprintf(stderr, "%s\n", str_err);
    exit(-1);
}

void
err_sys(const char *str_err)
{
    fprintf(stderr, "%s\n", str_err);
    exit(-1);
}

int
Socket(int faimly, int type, int protocol)
{
    int sockfd;
    if ( (sockfd = socket(faimly, type, protocol)) < 0)
        err_sys("socket error");

    return sockfd;
}

void
Connect(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
    if (connect(sockfd, myaddr, addrlen) < 0)
        err_sys("connect error");
}

void 
Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
    if (bind(sockfd, myaddr, addrlen) < 0)
        err_sys("bind error");
}

void 
Listen(int sockfd, int backlog)
{
    if (listen(sockfd, backlog) < 0)
        err_sys("listen error");
}

int
Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
{
    int connfd;

    connfd = accept(sockfd, cliaddr, addrlen);
    if (connfd < 0)
        err_sys("accept error");

    return connfd;
}

void
Close(int sockfd)
{
    if (close(sockfd) < 0)
        err_sys("close error");
}

//////////////////////////////////////////////////////////////////////////
// Writen begin 
//

ssize_t
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);
        }

        nleft   -= nwritten;
        ptr     += nwritten;
    }

    return (n);
}

void
Writen(int fd, void *ptr, size_t nbytes)
{
    if (writen(fd, ptr, nbytes) != nbytes)
        err_sys("writen error");
}

// 
// Writen end 
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// Readline begin
//

static int  read_cnt;
static char *read_ptr;
static char read_buf[MAXLINE];

static  ssize_t
my_read(int fd, char *ptr)
{
    if (read_cnt <= 0) {
        for ( ; ; ) {
            if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
                if (errno == EINTR) 
                    continue;
                return -1;
            } else if (read_cnt == 0)
                return 0;

            read_ptr = read_buf;
            break;
        }
    }

    read_cnt--;
    *ptr = *read_ptr++;
    return 1;
}

ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n;
    ssize_t rc;
    char    c;
    char    *ptr;

    ptr = vptr;
    for (n=1; n<maxlen; n++) {
        if ( (rc = my_read(fd, &c)) == 1) {
            *ptr++ = c;
            if (c == '\n')
                break;
        } else if (rc == 0) {
            *ptr = 0;       /* EOF, n - 1 bytes were read */
            return n-1;
        } else {
            return -1;
        }
    }

    *ptr = 0;
    return n;
}

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
    ssize_t n;

    if ( (n = readline(fd, ptr, maxlen)) < 0)
        err_sys("readline error");
    return n;
}

//
// Readline end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// wrapstdio begin
// 

// Fgets begin
char *
Fgets(char *ptr, int n, FILE *stream)
{
    char *rptr;

    if ( (rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
        err_sys("fgets error");

    return rptr;
}
// Fgets end

// Fputs begin
void
Fputs(const char *ptr, FILE *stream)
{
    if (fputs(ptr, stream) == EOF)
        err_sys("fputs error");
}
// Fputs end

// 
// wrapstdio end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// str_echo begin
//

void
str_echo(int sockfd)
{
    char    buf[MAXLINE];
    ssize_t n;

    for ( ; ; ) {
        // 從套接字讀取數據
        while ( (n = read(sockfd, buf, MAXLINE)) > 0)
            // 將讀取的數據發送給客戶端
            Writen(sockfd, buf, n);

        if (n < 0 && errno == EINTR)
            continue;
        else if (n < 0)
            err_sys("str_echo: read error");
        else
            break;
    }
}

//
// str_echo end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// str_cli begin
//

void
str_cli(FILE *fp, int sockfd)
{
    char    sendline[MAXLINE];
    char    recvline[MAXLINE];

    while (Fgets(sendline, MAXLINE, fp) != NULL) {
        Writen(sockfd, sendline, strlen(sendline));

        if (Readline(sockfd, recvline, MAXLINE) == 0)
            err_quit("str_cli: server terminated prematurely");

        Fputs(recvline, stdout);
    }
}

//
// str_cli end
//////////////////////////////////////////////////////////////////////////


int
main(int argc, char **argv)
{
    int                 sockfd;
    struct sockaddr_in  servaddr;

    if (argc != 2)
        err_quit("usage: tcpcli <IPaddress>");

    // 申請一個套接字
    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    // 設置一個服務器套接字
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(SERV_PORT);
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

    Connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    str_cli(stdin, sockfd);

    exit(0);
}   

服務端的代碼:

/*************************************************************************
    > File Name: tcpserv.c
    > Author: mhsheng
    > Mail:[email protected] 
    > Created Time: Mon 14 Nov 2016 10:35:23 AM CST
 ************************************************************************/

// c standard head file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <signal.h>

// system i/o head file
#include <unistd.h>

// socket head file
#include <netinet/in.h>

#define MAXLINE     1024
#define LISTENQ     5
#define SERV_PORT   9066    

void
err_quit(const char *str_err)
{
    fprintf(stderr, "%s\n", str_err);
    exit(-1);
}

void
err_sys(const char *str_err)
{
    fprintf(stderr, "%s\n", str_err);
    exit(-1);
}

int
Socket(int faimly, int type, int protocol)
{
    int sockfd;
    if ( (sockfd = socket(faimly, type, protocol)) < 0)
        err_sys("socket error");

    return sockfd;
}

void
Connect(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
    if (connect(sockfd, myaddr, addrlen) < 0)
        err_sys("connect error");
}

void 
Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
    if (bind(sockfd, myaddr, addrlen) < 0)
        err_sys("bind error");
}

void 
Listen(int sockfd, int backlog)
{
    if (listen(sockfd, backlog) < 0)
        err_sys("listen error");
}

int
Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
{
    int connfd;

    for ( ; ; ) {
        if ( (connfd = accept(sockfd, cliaddr, addrlen)) < 0) {
            if (errno == EINTR)         // 信號中斷引起的錯誤
                continue;
            else
                err_sys("accept error");
        }
        break;
    }

    return connfd;
}

void
Close(int sockfd)
{
    if (close(sockfd) < 0)
        err_sys("close error");
}

//////////////////////////////////////////////////////////////////////////
// Writen begin 
//

ssize_t
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);
        }

        nleft   -= nwritten;
        ptr     += nwritten;
    }

    return (n);
}

void
Writen(int fd, void *ptr, size_t nbytes)
{
    if (writen(fd, ptr, nbytes) != nbytes)
        err_sys("writen error");
}

// 
// Writen end 
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// Readline begin
//

static int  read_cnt;
static char *read_ptr;
static char read_buf[MAXLINE];

static  ssize_t
my_read(int fd, char *ptr)
{
    if (read_cnt <= 0) {
        for ( ; ; ) {
            if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
                if (errno == EINTR) 
                    continue;
                return -1;
            } else if (read_cnt == 0)
                return 0;

            read_ptr = read_buf;
            break;
        }
    }

    read_cnt--;
    *ptr = *read_ptr++;
    return 1;
}

ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n;
    ssize_t rc;
    char    c;
    char    *ptr;

    ptr = vptr;
    for (n=1; n<maxlen; n++) {
        if ( (rc = my_read(fd, &c)) == 1) {
            *ptr++ = c;
            if (c == '\n')
                break;
        } else if (rc == 0) {
            *ptr = 0;       /* EOF, n - 1 bytes were read */
            return n-1;
        } else {
            return -1;
        }
    }

    *ptr = 0;
    return n;
}

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
    ssize_t n;

    if ( (n = readline(fd, ptr, maxlen)) < 0)
        err_sys("readline error");
    return n;
}

//
// Readline end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// wrapstdio begin
// 

// Fgets begin
char *
Fgets(char *ptr, int n, FILE *stream)
{
    char *rptr;

    if ( (rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
        err_sys("fgets error");

    return rptr;
}
// Fgets end

// Fputs begin
void
Fputs(const char *ptr, FILE *stream)
{
    if (fputs(ptr, stream) == EOF)
        err_sys("fputs error");
}
// Fputs end

// 
// wrapstdio end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// str_echo begin
//

void
str_echo(int sockfd)
{
    char    buf[MAXLINE];
    ssize_t n;

    for ( ; ; ) {
        // 從套接字讀取數據
        while ( (n = read(sockfd, buf, MAXLINE)) > 0)
            // 將讀取的數據發送給客戶端
            Writen(sockfd, buf, n);

        if (n < 0 && errno == EINTR)
            continue;
        else if (n < 0)
            err_sys("str_echo: read error");
        else
            break;
    }
}

//
// str_echo end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// str_cli begin
//

void
str_cli(FILE *fp, int sockfd)
{
    char    sendline[MAXLINE];
    char    recvline[MAXLINE];

    while (Fgets(sendline, MAXLINE, fp) != NULL) {
        Writen(sockfd, sendline, strlen(sendline));

        if (Readline(sockfd, recvline, MAXLINE) == 0)
            err_quit("str_cli: server terminated prematurely");

        Fputs(recvline, stdout);
    }
}

//
// str_cli end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// signal begin
//
typedef void Sigfunc(int); 

Sigfunc *
signal(int signo, Sigfunc *func)
{
    struct sigaction    act;
    struct sigaction    oact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;
#endif
    } else {
#ifdef SA_RESTART
        act.sa_flags |= SA_RESTART;
#endif
    }


    if (sigaction(signo, &act, &oact) < 0)
        return SIG_ERR;

    return oact.sa_handler;
}

Sigfunc *
Signal(int signo, Sigfunc *func)
{
    Sigfunc *sigfunc;

    if ( (sigfunc = signal(signo, func)) == SIG_ERR) 
        err_sys("signal error");

    return sigfunc;
}

//
// signal end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
//
//

void
Waitpid(pid_t pid) 
{
    if (waitpid(pid, NULL, 0) != pid) {
        err_sys("waitpid error");
    }
}

//
//
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// sig_chld begin
//

void
sig_chld(int signo)
{   
    pid_t   pid;
    int     stat;

    while ( (pid = waitpid(-1, &stat, WNOHANG)) < 0)
        ;

    return ;
}

//
// sig_chld end
//////////////////////////////////////////////////////////////////////////


int
main(int argc, char **argv)
{
    int                 listenfd;
    int                 connfd;
    pid_t               childpid;
    pid_t               grandchildpid;
    struct sockaddr_in  servaddr;

    void sig_chld(int);

    // 創建一個監聽套接字描述符
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    // 設置服務器的監聽套接字
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family         = AF_INET;
    servaddr.sin_port           = htons(SERV_PORT);
    servaddr.sin_addr.s_addr    = htonl(INADDR_ANY);

    // 綁定套接字到套接字描述符
    Bind(listenfd, (struct sockaddr *) & servaddr, sizeof(servaddr));

    // 啓動監聽套接字
    Listen(listenfd, LISTENQ);  

    for ( ; ; ) {
        connfd = Accept(listenfd, (struct sockaddr *)NULL, NULL);

        if ( (childpid = fork()) == 0) {
            if ( (grandchildpid = fork()) == 0) {
                Close(listenfd);

                str_echo(connfd);

                Close(connfd);
                exit(0);
            }
            Close(listenfd);
            Close(connfd);

            exit(0);
        }

        Waitpid(childpid);

        Close(connfd);
    }

    exit(0);
}   

Makefile 文件:

PROGS   = tcpserv \
          tcpcli

OBJS    = tcpserv.o \
          tcpcli.o

All:    ${PROGS}

tcpserv:    tcpserv.o
    cc -o tcpserv tcpserv.o

tcpcli:     tcpcli.o
    cc -o tcpcli tcpcli.o

clean:
    rm $(PROGS) $(OBJS)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章