UNP函数笔记十七: 客户/服务器程序设计范式

58 篇文章 0 订阅
49 篇文章 0 订阅

第三十章  客户/服务器程序设计范式:


示例:

#include "err_exit.h"
#include <sys/mman.h>

/*
 * Allocate an array of "nchildren" longs in shared memory that can
 * be used as a counter by each child of how many clients it services.
 * See pp. 467-470 of "Advanced Programming in the Unix Environment."
 */

long * 
meter(int nchildren)
{
    int    fd;
    long * ptr;

#ifdef MAP_ANON
    if ((ptr = mmap(0, nchildren*sizeof(long), PROT_READ | PROT_WRITE, 
                    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) {
        err_exit("mmap error");
    }
#else
    if ((fd = open("/dev/zero", O_RDWR, 0)) == -1) {
        err_exit("open /dev/zero error");
    }

    if ((ptr = mmap(0, nchildren*sizeof(long), PROT_READ | PROT_WRITE, 
                    MAP_SHARED, fd, 0)) == MAP_FAILED) {
        err_exit("mmap error");
    }
    Close(fd);
#endif

    return(ptr);
}

#include "myio.h"
#include "warp.h"
#include "tcp_connect.h"

#define MAXN 16384  /* max # bytes to request from server */

int 
main(int argc, char ** argv)
{
    int      i;
    int      j;
    int      fd;
    int      nchildren;
    int      nloops;
    int      nbytes;
    pid_t    pid;
    ssize_t  n;
    char     request[MAXLINE];
    char     reply[MAXN];

    if (argc != 6) {
        printf("usage: client <hostname or IPaddr> <port> <#children> "
               "<#loops/child> <#bytes/request>\n");
        exit(1);
    }

    nchildren = atoi(argv[3]);
    nloops = atoi(argv[4]);
    nbytes = atoi(argv[5]);
    snprintf(request, sizeof(request), "%d\n", nbytes);  /* newline at end */

    for (i = 0; i < nchildren; i++) {
        if ((pid = Fork()) == 0) {  /* child */
            for (j = 0; j < nloops; j++) {
                fd = tcp_connect(argv[1], argv[2]);

                n = strlen(request);
                if (write(fd, request, n) != n) {
                    err_msg("write error", errno);
                }

                if ((n = readn(fd, reply, nbytes)) != nbytes) {
                    err_msg("readn error", errno);
                }

                Close(fd);  /* TIME_WAIT on client, not server */
            }
            printf("child %d done\n", i);
            exit(0);
        }
        /* parent loops around to fork() again */
    }

    while (wait(NULL) > 0) {  /* now parent waits for all children */

    }

    if (errno != ECHILD) {
        err_msg("wait error", errno);
    }

    exit(0);
}

#ifndef __READLINE_R_H__
#define __READLINE_R_H__


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#ifndef MAXLINE
#define MAXLINE 4096
#endif

typedef struct {
    int      read_fd;      /* caller's descriptor to read from */
    char   * read_ptr;     /* caller's buffer to read into */
    size_t   read_maxlen;  /* max #bytes to read */
    int      rl_cnt;       /* initialize to 0 */
    char   * rl_bufptr;    /* initialize to rl_buf */
    char     rl_buf[MAXLINE];
} Rline;

ssize_t 
my_read_r(Rline * rptr, char * ptr)
{
    if (rptr->rl_cnt <= 0) {
again:
        rptr->rl_cnt = read(rptr->read_fd, rptr->rl_buf, sizeof(rptr->rl_buf));
        if (rptr->rl_cnt < 0) {
            if (errno == EINTR) {
                goto again;
            }
            else {
                return(-1);
            }
        }
        else if (rptr->rl_cnt == 0) {
            return(0);
        }
        rptr->rl_bufptr = rptr->rl_buf;
    }

    rptr->rl_cnt--;
    *ptr = *rptr->rl_bufptr++ & 255;
    return(1);
}

void 
readline_rinit(int fd, void * ptr, size_t maxlen, Rline * rptr)
{
    rptr->read_fd = fd;  /* save caller's arguments */
    rptr->read_ptr = ptr;
    rptr->read_maxlen = maxlen;

    rptr->rl_cnt = 0;  /* and init our counter & pointer */
    rptr->rl_bufptr = rptr->rl_buf;
}

ssize_t 
readline_r(Rline * rptr)
{
    int    n;
    int    rc;
    char   c; 
    char * ptr;

    ptr = rptr->read_ptr;
    for (n = 1; n < rptr->read_maxlen; n++) {
        if ((rc = my_read_r(rptr, &c)) == 1) {
            *ptr++ = c;
            if (c == '\n') {
                break;
            }
        }
        else if (rc == 0) {
            if (n == 1) {
                return(0);  /* EOF, no data read */
            }
            else {
                break;  /* EOF, some data was read */
            }
        }
        else {
            return(-1);  /* error */
        }
    }

    *ptr = 0;
    return(n);
}

ssize_t 
Readline_r(Rline * rptr)
{
    ssize_t n = readline_r(rptr);
    if (n == -1) {
        printf("readline_r error : %s\n", strerror(errno));
    }
    return(n);
}


#endif

#include "readline_r.h"

#define MAXN 16384  /* max #bytes that a client can request */

void 
web_child(int sockfd)
{
    int      ntowrite;
    ssize_t  nread;
    char     line[MAXLINE];
    char     result[MAXN];
    Rline    rline;

    readline_rinit(sockfd, line, MAXLINE, &rline);
    for ( ; ; ) {
        if ((nread = Readline_r(&rline)) == 0) {
            return;  /* connection closed by other end */
        }

        /* line from client specifies #bytes to write back */
        ntowrite = atol(line);
        if ((ntowrite <= 0) || (ntowrite > MAXN)) {
            printf("client request for %d bytes\n", ntowrite);
            exit(1);
        }

        if (writen(sockfd, result, ntowrite) != ntowrite) {
            printf("writen error : %s\n", strerror(errno));
            exit(1);
        }
    }
}

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/resource.h>

void 
pr_cpu_time(void)
{
    double         user;
    double         sys;
    struct rusage  myusage;
    struct rusage  childusage;

    if (getrusage(RUSAGE_SELF, &myusage) < 0) {
        printf("getrusage error : %s\n", strerror(errno));
        exit(1);
    }
    if (getrusage(RUSAGE_CHILDREN, &childusage) < 0) {
        printf("getrusage error : %s\n", strerror(errno));
        exit(1);
    }

    user = (double)myusage.ru_utime.tv_sec + 
                   myusage.ru_utime.tv_usec/1000000.0;
    user += (double)childusage.ru_utime.tv_sec + 
                    childusage.ru_utime.tv_usec/1000000.0;
    sys = (double)myusage.ru_stime.tv_sec + 
                  myusage.ru_stime.tv_usec/1000000.0;
    sys += (double)childusage.ru_stime.tv_sec + 
                   childusage.ru_stime.tv_usec/1000000.0;

    printf("\nuser time = %g, sys time = %g\n", user, sys);
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

void 
sig_int(int signo)
{
    pr_cpu_time();
    exit(0);
}

int 
main(int argc, char ** argv)
{
    int               listenfd;
    int               connfd;
    socklen_t         clilen;
    socklen_t         addrlen;
    struct sockaddr * cliaddr;

    if (argc == 2) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 3) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#>\n", argv[0]);
        exit(1);
    }

    cliaddr = Malloc(addrlen);

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        clilen = addrlen;
        connfd = Accept(listenfd, cliaddr, &clilen);

        web_child(connfd);  /* process the request */

        Close(connfd);  /* parent closes connected socket */
    }
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

void 
sig_int(int signo)
{
    pr_cpu_time();
    exit(0);
}

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

    while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
        /* printf("child %d terminated\n", pid); */
    }
    return;
}

int 
main(int argc, char ** argv)
{
    int               listenfd;
    int               connfd;
    pid_t             childpid;
    socklen_t         clilen;
    socklen_t         addrlen;
    struct sockaddr * cliaddr;

    if (argc == 2) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 3) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#>\n", argv[0]);
        exit(1);
    }

    cliaddr = Malloc(addrlen);

    if (my_signal(SIGCHLD, sig_chld) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }
    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        clilen = addrlen;
        if ((connfd = accept(listenfd, cliaddr, &clilen)) < 0) {
            if (errno == EINTR) {
                continue;  /* back to for() */
            }
            else {
                err_msg("accept error", errno);
                exit(1);
            }
        }

        if ((childpid = Fork()) == 0) {  /* child process */
            Close(listenfd);  /* close listening socket */
            web_child(connfd);  /* process request */
            exit(0);
        }
        Close(connfd);  /* parent closes connected socket */
    }
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

int     nchildren;
pid_t * pids;

void 
sig_int(int signo)
{
    int  i;

    /* terminate all children */
    for (i = 0; i < nchildren; i++) {
        kill(pids[i], SIGTERM);
    }
    while (wait(NULL) > 0) {  /* wait for all children */
    
    }
    if (errno != ECHILD) {
        err_msg("wait error", errno);
    }

    pr_cpu_time();
    exit(0);
}

void 
child_main(int i, int listenfd, int addrlen)
{
    int               connfd;
    socklen_t         clilen;
    struct sockaddr * cliaddr;

    cliaddr = Malloc(addrlen);

    printf("child %ld starting\n", (long)getpid());
    for ( ; ; ) {
        clilen = addrlen;
        connfd = Accept(listenfd, cliaddr, &clilen);

        web_child(connfd);  /* process the request */
        Close(connfd);
    }
}

pid_t 
child_make(int i, int listenfd, int addrlen)
{
    pid_t  pid;

    if ((pid = Fork()) > 0) {
        return(pid);  /* parent */
    }

    child_main(i, listenfd, addrlen);  /* never returns */
}

int 
main(int argc, char ** argv)
{
    int        listenfd;
    int        i;
    socklen_t  addrlen;

    if (argc == 3) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 4) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
        exit(1);
    }

    nchildren = atoi(argv[argc-1]);
    pids = Calloc(nchildren, sizeof(pid_t));

    for (i = 0; i < nchildren; i++) {
        pids[i] = child_make(i, listenfd, addrlen);  /* parent returns */
    }

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        pause();  /* everything done by children */
    }
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

int     nchildren;
pid_t * pids;

struct flock  lock_it;
struct flock  unlock_it;
int    lock_fd = -1;  /* fcntl() will fail if my_lock_init() not called */

void 
my_lock_init(char * pathname)
{
    char  lock_file[1024];

    /* must copy caller's string, in case it's a constant */
    strncpy(lock_file, pathname, sizeof(lock_file));
    if ((lock_fd = mkstemp(lock_file)) == -1) {
        printf("mkstemp error : %s\n", strerror(errno));
        exit(1);
    }

    if (unlink(lock_file) == -1) {  /* but lock_fd remains open */
        printf("unlink error : %s\n", strerror(errno));
        exit(1);
    }

    lock_it.l_type = F_WRLCK;
    lock_it.l_whence = SEEK_SET;
    lock_it.l_start = 0;
    lock_it.l_len = 0;

    unlock_it.l_type = F_UNLCK;
    unlock_it.l_whence = SEEK_SET;
    unlock_it.l_start = 0;
    unlock_it.l_len = 0;
}

void 
my_lock_wait()
{
    while (fcntl(lock_fd, F_SETLKW, &lock_it) == -1) {
        if (errno == EINTR) {
            continue;
        }
        else {
            printf("fcntl error for my_lock_wait\n");
            exit(1);
        }
    }
}

void 
my_lock_release()
{
    if (fcntl(lock_fd, F_SETLKW, &unlock_it) == -1) {
        printf("fcntl error for my_lock_release\n");
        exit(1);
    }
}

void 
child_main(int i, int listenfd, int addrlen)
{
    int               connfd;
    socklen_t         clilen;
    struct sockaddr * cliaddr;

    cliaddr = Malloc(addrlen);

    printf("child %ld starting\n", (long)getpid());
    for ( ; ; ) {
        clilen = addrlen;
        my_lock_wait();
        connfd = Accept(listenfd, cliaddr, &clilen);
        my_lock_release();

        web_child(connfd);  /* process the request */
        Close(connfd);
    }
}

pid_t 
child_make(int i, int listenfd, int addrlen)
{
    pid_t  pid;

    if ((pid = Fork()) > 0) {
        return(pid);  /* parent */
    }

    child_main(i, listenfd, addrlen);  /* never returns */
}

void 
sig_int(int signo)
{
    int  i;

    /* terminate all children */
    for (i = 0; i < nchildren; i++) {
        kill(pids[i], SIGTERM);
    }
    while (wait(NULL) > 0) {  /* wait for all children */

    }
    if (errno != ECHILD) {
        err_msg("wait error", errno);
    }

    pr_cpu_time();
    exit(0);
}

int 
main(int argc, char ** argv)
{
    int        listenfd;
    int        i;
    socklen_t  addrlen;

    if (argc == 3) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 4) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
        exit(1);
    }

    nchildren = atoi(argv[argc-1]);
    pids = Calloc(nchildren, sizeof(pid_t));

    my_lock_init("/tmp/lock.XXXXXX");  /* one lock file for all children */
    for (i = 0; i < nchildren; i++) {
        pids[i] = child_make(i, listenfd, addrlen);  /* parent returns */
    }

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        pause();  /* everything done by children */
    }
}

#include <fcntl.h>
#include <sys/mman.h>

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

int     nchildren;
pid_t * pids;

pthread_mutex_t * mptr;  /* actual mutex will be in shared memory */

void 
my_lock_init(char * pathname)
{
    int                  fd;
    int                  error;
    pthread_mutexattr_t  mattr;

    if ((fd = open("/dev/zero", O_RDWR, 0)) == -1) {
        err_msg("open /dev/zero error", errno);
    }

    if ((mptr = mmap(0, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE,
                     MAP_SHARED, fd, 0)) == MAP_FAILED) {
        err_msg("mmap error", errno);
    }
    Close(fd);

    if ((error = pthread_mutexattr_init(&mattr)) != 0) {
        err_msg("pthread_mutexattr_init error", error);
    }
    if ((error = pthread_mutexattr_setpshared(&mattr, 
                     PTHREAD_PROCESS_SHARED)) != 0) { /* process lock */
        err_msg("pthread_mutexattr_setpshared error", error);
    }
    if ((error = pthread_mutex_init(mptr, &mattr)) != 0) {
        err_msg("pthread_mutex_init error", error);
    }
}

void 
my_lock_wait()
{
    Pthread_mutex_lock(mptr);
}

void 
my_lock_release()
{
    Pthread_mutex_unlock(mptr);
}

void 
child_main(int i, int listenfd, int addrlen)
{
    int               connfd;
    socklen_t         clilen;
    struct sockaddr * cliaddr;

    cliaddr = Malloc(addrlen);

    printf("child %ld starting\n", (long)getpid());
    for ( ; ; ) {
        clilen = addrlen;
        my_lock_wait();
        connfd = Accept(listenfd, cliaddr, &clilen);
        my_lock_release();

        web_child(connfd);  /* process the request */
        Close(connfd);
    }
}

pid_t 
child_make(int i, int listenfd, int addrlen)
{
    pid_t  pid;

    if ((pid = Fork()) > 0) {
        return(pid);  /* parent */
    }

    child_main(i, listenfd, addrlen);  /* never returns */
}

void 
sig_int(int signo)
{
    int  i;

    /* terminate all children */
    for (i = 0; i < nchildren; i++) {
        kill(pids[i], SIGTERM);
    }
    while (wait(NULL) > 0) {  /* wait for all children */

    }
    if (errno != ECHILD) {
        err_msg("wait error", errno);
    }

    pr_cpu_time();
    exit(0);
}

int 
main(int argc, char ** argv)
{
    int        listenfd;
    int        i;
    socklen_t  addrlen;

    if (argc == 3) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 4) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
        exit(1);
    }

    nchildren = atoi(argv[argc-1]);
    pids = Calloc(nchildren, sizeof(pid_t));

    my_lock_init(NULL);
    for (i = 0; i < nchildren; i++) {
        pids[i] = child_make(i, listenfd, addrlen);  /* parent returns */
    }

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        pause();  /* everything done by children */
    }
}

#include <unistd.h>

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "read_fd.h"
#include "write_fd.h"
#include "web_child.h"
#include "pr_cpu_time.h"

#define   max(a, b)       ((a) > (b) ? (a) : (b))

typedef struct {
    pid_t  child_pid;     /* process ID */
    int    child_pipefd;  /* parent's stream pipe to/from child */
    int    child_status;  /* 0 = ready */
    long   child_count;   /* # connections handled */
} Child;

Child  * cptr;  /* array of Child structures; calloc'ed */

int  nchildren;

void 
child_main(int i, int listenfd, int addrlen)
{
    char     c;
    int      connfd;
    ssize_t  n;

    printf("child %ld starting\n", (long)getpid());
    for ( ; ; ) {
        if ((n = read_fd(STDERR_FILENO, &c, 1, &connfd)) < 0) {
            err_msg("read_fd error", errno);
        }
        else if (n == 0) {
            printf("read_fd returned 0\n");
            exit(1);
        }

        if (connfd < 0) {
            printf("no descriptor from read_fd\n");
            exit(1);
        }

        web_child(connfd);  /* process request */
        Close(connfd);

        /* tell parent we're ready again */
        if (write(STDERR_FILENO, "", 1) != 1) {
            err_msg("write error", errno);
        }
    }
}

pid_t 
child_make(int i, int listenfd, int addrlen)
{
    int    sockfd[2];
    pid_t  pid;

    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) == -1) {
        err_msg("socketpair error", errno);
    }

    if ((pid = Fork()) > 0) {
        Close(sockfd[1]);
        cptr[i].child_pid = pid;
        cptr[i].child_pipefd = sockfd[0];
        cptr[i].child_status = 0;
        return(pid);        /* parent */
    }

    /* child's stream pipe to parent */
    if (dup2(sockfd[1], STDERR_FILENO) == -1) {
        err_msg("dup2 error", errno);
    }
    Close(sockfd[0]);
    Close(sockfd[1]);
    Close(listenfd);  /* child does not need this open */
    child_main(i, listenfd, addrlen);  /* never returns */
}

void 
sig_int(int signo)
{
    int  i;

    /* terminate all children */
    for (i = 0; i < nchildren; i++) {
        kill(cptr[i].child_pid, SIGTERM);
    }
    while (wait(NULL) > 0) {  /* wait for all children */

    }
    if (errno != ECHILD) {
        err_msg("wait error", errno);
    }

    pr_cpu_time();

    for (i = 0; i < nchildren; i++) {
        printf("child %d, %ld connections\n", i, cptr[i].child_count);
    }

    exit(0);
}

int 
main(int argc, char ** argv)
{
    int               listenfd;
    int               i;
    int               navail;
    int               maxfd;
    int               nsel;
    int               connfd;
    int               rc;
    ssize_t           n;
    fd_set            rset;
    fd_set            masterset;
    socklen_t         addrlen;
    socklen_t         clilen;
    struct sockaddr * cliaddr;

    if (argc == 3) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 4) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
        exit(1);
    }

    FD_ZERO(&masterset);
    FD_SET(listenfd, &masterset);
    maxfd = listenfd;
    cliaddr = Malloc(addrlen);

    nchildren = atoi(argv[argc-1]);
    navail = nchildren;
    cptr = Calloc(nchildren, sizeof(Child));

    /* prefork all the children */
    for (i = 0; i < nchildren; i++) {
        child_make(i, listenfd, addrlen);  /* parent returns */
        FD_SET(cptr[i].child_pipefd, &masterset);
        maxfd = max(maxfd, cptr[i].child_pipefd);
    }

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        rset = masterset;
        if (navail <= 0) {
            FD_CLR(listenfd, &rset);  /* turn off if no available children */
        }
        if ((nsel = select(maxfd + 1, &rset, NULL, NULL, NULL)) == -1) {
            err_msg("select error", errno);
        }

        /* check for new connections */
        if (FD_ISSET(listenfd, &rset)) {
            clilen = addrlen;
            connfd = Accept(listenfd, cliaddr, &clilen);

            for (i = 0; i < nchildren; i++) {
                if (cptr[i].child_status == 0) {
                    break;  /* available */
                }
            }

            if (i == nchildren) {
                printf("no available children\n");
                exit(1);
            }
            cptr[i].child_status = 1;  /* mark child as busy */
            cptr[i].child_count++;
            navail--;

            if ((n = write_fd(cptr[i].child_pipefd, "", 1, connfd)) < 0) {
                err_msg("write_fd error", errno);
            }
            Close(connfd);
            if (--nsel == 0) {
                continue;  /* all done with select() results */
            }
        }

        /* find any newly-available children */
        for (i = 0; i < nchildren; i++) {
            if (FD_ISSET(cptr[i].child_pipefd, &rset)) {
                if ((n = read(cptr[i].child_pipefd, &rc, 1)) < 0) {
                    err_msg("read error", errno);
                }
                else if (n == 0) {
                    printf("child %d terminated unexpectedly\n", i);
                    exit(1);
                }
                cptr[i].child_status = 0;
                navail++;
                if (--nsel == 0) {
                    break;  /* all done with select() results */
                }
            }
        }
    }
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

void * 
doit(void * arg)
{
    Pthread_detach(pthread_self());
    web_child((int)arg);
    Close((int)arg);
    return(NULL);
}

void 
sig_int(int signo)
{
    pr_cpu_time();
    exit(0);
}

int 
main(int argc, char ** argv)
{
    int               listenfd;
    int               connfd;
    pthread_t         tid;
    socklen_t         clilen;
    socklen_t         addrlen;
    struct sockaddr * cliaddr;

    if (argc == 2) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 3) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#>\n", argv[0]);
        exit(1);
    }

    cliaddr = (struct sockaddr *)Malloc(addrlen);

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        clilen = addrlen;
        connfd = Accept(listenfd, cliaddr, &clilen);

        Pthread_create(&tid, NULL, &doit, (void *)connfd);
    }
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

typedef struct {
    pthread_t  thread_tid;    /* thread ID */
    long       thread_count;  /* # connections handled */
} Thread;

Thread * tptr;  /* array of Thread structures; calloc'ed */

int              listenfd;
int              nthreads;
socklen_t        addrlen;
pthread_mutex_t  mlock = PTHREAD_MUTEX_INITIALIZER;

void * 
thread_main(void * arg)
{
    int               connfd;
    socklen_t         clilen;
    struct sockaddr * cliaddr;

    cliaddr = Malloc(addrlen);

    printf("thread %d starting\n", (int) arg);
    for ( ; ; ) {
        clilen = addrlen;
        Pthread_mutex_lock(&mlock);
        connfd = Accept(listenfd, cliaddr, &clilen);
        Pthread_mutex_unlock(&mlock);
        tptr[(int)arg].thread_count++;

        web_child(connfd);  /* process request */
        Close(connfd);
    }
}

void 
thread_make(int i)
{
    Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *)i);
    return;   /* main thread returns */
}

void 
sig_int(int signo)
{
    int  i;

    pr_cpu_time();

    for (i = 0; i < nthreads; i++) {
        printf("thread %d, %ld connections\n", i, tptr[i].thread_count);
    }

    exit(0);
}

int 
main(int argc, char ** argv)
{
    int  i;

    if (argc == 3) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 4) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#> <#threads>\n", argv[0]);
        exit(1);
    }

    nthreads = atoi(argv[argc-1]);
    tptr = Calloc(nthreads, sizeof(Thread));

    for (i = 0; i < nthreads; i++) {
        thread_make(i);  /* only main thread returns */
    }

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        pause();  /* everything done by threads */
    }
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

typedef struct {
    pthread_t  thread_tid;    /* thread ID */
    long       thread_count;  /* # connections handled */
} Thread;

Thread * tptr;  /* array of Thread structures; calloc'ed */

#define MAXNCLI  32

int              clifd[MAXNCLI];
int              iget;
int              iput;
pthread_mutex_t  clifd_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t   clifd_cond = PTHREAD_COND_INITIALIZER;
int              nthreads;

void * 
thread_main(void * arg)
{
    int  connfd;

    printf("thread %d starting\n", (int)arg);
    for ( ; ; ) {
        Pthread_mutex_lock(&clifd_mutex);
        while (iget == iput) {
            Pthread_cond_wait(&clifd_cond, &clifd_mutex);
        }
        connfd = clifd[iget];  /* connected socket to service */
        if (++iget == MAXNCLI) {
            iget = 0;
        }
        Pthread_mutex_unlock(&clifd_mutex);
        tptr[(int)arg].thread_count++;

        web_child(connfd);  /* process request */
        Close(connfd);
    }
}

void 
thread_make(int i)
{
    Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *)i);
    return;   /* main thread returns */
}

void 
sig_int(int signo)
{
    int  i;

    pr_cpu_time();

    for (i = 0; i < nthreads; i++) {
        printf("thread %d, %ld connections\n", i, tptr[i].thread_count);
    }

    exit(0);
}

int 
main(int argc, char ** argv)
{
    int               i;
    int               listenfd;
    int               connfd;
    socklen_t         addrlen;
    socklen_t         clilen;
    struct sockaddr * cliaddr;

    if (argc == 3) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 4) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#> <#threads>\n", argv[0]);
    }

    cliaddr = Malloc(addrlen);

    nthreads = atoi(argv[argc-1]);
    tptr = Calloc(nthreads, sizeof(Thread));
    iget = iput = 0;

    /* create all the threads */
    for (i = 0; i < nthreads; i++) {
        thread_make(i);  /* only main thread returns */
    }

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        clilen = addrlen;
        connfd = Accept(listenfd, cliaddr, &clilen);

        Pthread_mutex_lock(&clifd_mutex);
        clifd[iput] = connfd;
        if (++iput == MAXNCLI) {
            iput = 0;
        }
        if (iput == iget) {
            printf("iput = iget = %d\n", iput); /* children too less to hold */
            exit(1);
        }
        Pthread_cond_signal(&clifd_cond);
        Pthread_mutex_unlock(&clifd_mutex);
    }
}

#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"

typedef struct {
    pthread_t  thread_tid;    /* thread ID */
    long       thread_count;  /* #connections handled */
} Thread;

Thread  * tptr;  /* array of Thread structures; calloc'ed */

int        listenfd;
int        nthreads;
socklen_t  addrlen;

void * 
thread_main(void * arg)
{
    int               connfd;
    socklen_t         clilen;
    struct sockaddr * cliaddr;

    cliaddr = Malloc(addrlen);

    printf("thread %d starting\n", (int)arg);
    for ( ; ; ) {
        clilen = addrlen;
        connfd = Accept(listenfd, cliaddr, &clilen);
        tptr[(int)arg].thread_count++;

        web_child(connfd);  /* process the request */
        Close(connfd);
    }
}

void 
thread_make(int i)
{
    Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *)i);
    return;  /* main thread returns */
}

void 
sig_int(int signo)
{
    int  i;

    pr_cpu_time();

    for (i = 0; i < nthreads; i++) {
        printf("thread %d, %ld connections\n", i, tptr[i].thread_count);
    }

    exit(0);
}

int 
main(int argc, char ** argv)
{
    int  i;

    if (argc == 3) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 4) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: %s [ <host> ] <port#> <#threads>\n", argv[0]);
        exit(1);
    }

    nthreads = atoi(argv[argc-1]);
    tptr = Calloc(nthreads, sizeof(Thread));

    for (i = 0; i < nthreads; i++) {
        thread_make(i);  /* only main thread returns */
    }

    if (my_signal(SIGINT, sig_int) == SIG_ERR) {
        err_msg("my_signal error", errno);
    }

    for ( ; ; ) {
        pause();  /* everything done by threads */
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值