CSAPP 并发编程示例

1.基于进程的并发编程
#include "csapp.h"

void echo(int connfd);

void sigchld_handler(int sig)
{
    while (waitpid(-1, 0, WNOHANG) > 0) //准备好接受多个僵死进程
        ;
    return;
}

int main(int argc, char **argv)
{
    int listenfd, connfd, port, clientlen = sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    struct hostent *hp;
    char *haddrp;
    if (argc != 2)
    {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(0);
    }
    port = atoi(argv[1]);
    Signal(SIGCHLD, sigchld_handler); //回收子进程

    listenfd = Open_listenfd(port);
    while (1)
    {
        connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);

        if (Fork() == 0)
        {
            Close(listenfd); //关闭复制过来的监听描述符
            hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
                sizeof(clientaddr.sin_addr.s_addr), AF_INET);
            haddrp = inet_ntoa(clientaddr.sin_addr);
            printf("server connected to %s (%s)\n", hp->h_name, haddrp);
            echo(connfd);
            Close(connfd);
            exit(0);
        }

        Close(connfd);
    }
    exit(0);
}
2.基于I/O多路复用,实现了多个客户端的echo服务器
#include "csapp.h"

typedef struct
{
    int maxfd;
    fd_set read_set;
    fd_set ready_set;
    int nready;
    int maxi;
    int clientfd[FD_SETSIZE];
    rio_t clientrio[FD_SETSIZE];
}pool;

void init_pool(int listenfd, pool* p);
void add_client(int connfd, pool* p);
void check_clients(pool* p);

int byte_cnt=0;

int main(int argc, char **argv)
{
    int listenfd, connfd, port, clientlen = sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    struct hostent *hp;
    static pool pool;
    char *haddrp;
    fd_set read_set,ready_set;
    if (argc != 2)
    {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(0);
    }
    port = atoi(argv[1]);
    listenfd = Open_listenfd(port);
    init_pool(listenfd, &pool);

    while (1)
    {
        pool.ready_set = pool.read_set;//重新载入
        pool.nready = Select(pool.maxfd+1, &pool.ready_set, NULL, NULL, NULL);
        if(FD_ISSET(listenfd, &pool.ready_set))
        {
            connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);

            hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
                                sizeof(clientaddr.sin_addr.s_addr), AF_INET);
            haddrp = inet_ntoa(clientaddr.sin_addr);
            printf("server connected to %s (%s)\n", hp->h_name, haddrp);
            add_client(connfd, &pool);
        }
        check_clients(&pool);
    }
    exit(0);
}
void init_pool(int listenfd, pool* p)
{
    int i;
    p->maxi = -1;
    for(i=0; i<FD_SETSIZE; i++)
        p->clientfd[i] = -1;
    p->maxfd = listenfd;
    FD_ZERO(&p->read_set);
    FD_SET(listenfd, &p->read_set);
}
void add_client(int connfd, pool* p)
{
    int i;
    p->nready--;
    for (i = 0; i < FD_SETSIZE; i++)
        if (p->clientfd[i] < 0)
        {
            p->clientfd[i] = connfd;
            Rio_readinitb(&p->clientrio[i], connfd);
            FD_SET(connfd, &p->read_set);
            if (connfd > p->maxfd)
                p->maxfd = connfd;
            if (i > p->maxi)
                p->maxi = i;
            break;
        }
        if(i == FD_SETSIZE)
            app_error("add_client error: Too many clients");
}
void check_clients(pool* p)
{
    int i, connfd, n;
    char buf[MAXLINE];
    rio_t rio;
    for (i = 0; (i <= p->maxi) && (p->nready > 0); i++)
    {
        connfd = p->clientfd[i];
        rio = p->clientrio[i];
        if ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0)
        {
            byte_cnt +=n;
            printf("Server received %d (%d total) bytes on fd %d\n",
                    n, byte_cnt, connfd);
            Rio_writen(connfd, buf, n);
        }
        else
        {
            Close(connfd);
            FD_CLR(connfd, &p->read_set);
            p->clientfd[i] = -1;
        }
    }
}
3.基于多线程,实现了多个客户端的echo服务器
#include "csapp.h"

void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
            void * (*routine)(void *), void *argp)
{
    int rc;

    if ((rc = pthread_create(tidp, attrp, routine, argp)) != 0)
    posix_error(rc, "Pthread_create error");
}

//常常配合pthread_self,来终止当前线程
void Pthread_cancel(pthread_t tid)
{
    int rc;

    if ((rc = pthread_cancel(tid)) != 0)
        posix_error(rc, "Pthread_cancel error");
}

//阻塞, 直到等到指定的线程终止。
void Pthread_join(pthread_t tid, void **thread_return)
{
    int rc;

    if ((rc = pthread_join(tid, thread_return)) != 0)
        posix_error(rc, "Pthread_join error");
}

//线程默认是可结合的:意味着可以被其他线程收回资源和杀死
//该函数使线程变为分离的,那么 其资源就不必显式的回收了。
void Pthread_detach(pthread_t tid)
{
    int rc;
    if ((rc = pthread_detach(tid)) != 0)
        posix_error(rc, "Pthread_detach error");
}

//线程显示终止
//主线程调用,等待所有其他线程终止,然后终止主线程和整个进程
void Pthread_exit(void *retval)
{
    pthread_exit(retval);
}
//某个 线程调用exit,会终止进程以及所有与该进程相关的线程

//返回自己线程的ID
pthread_t Pthread_self(void)
{
    return pthread_self();
}

void Pthread_once(pthread_once_t *once_control, void (*init_function)()) {
    pthread_once(once_control, init_function);
}


void echo(int connfd);
void* thread(void* vargp);

int main(int argc, char **argv)
{
    int listenfd, *connfdp, port, clientlen = sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    pthread_t tid;
    if (argc != 2)
    {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(0);
    }
    port = atoi(argv[1]);
    listenfd = Open_listenfd(port);

    while (1)
    {
        connfdp = (int*)Malloc(sizeof(int));
        *connfdp =Accept(listenfd, (SA *)&clientaddr, &clientlen);
        Pthread_create(&tid, NULL, thread, connfdp);
    }
    exit(0);
}

void* thread(void* vargp)
{
    int connfd = *((int*)vargp);
    printf("server connected to a client.\n");   
    Free(vargp);
    echo(connfd);
    Close(connfd);
    return NULL;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值