以线程实现TCP并发服务器

来源:互联网 发布:java如何取绝对值 编辑:程序博客网 时间:2024/06/05 08:25

对服务器来说,以线程为客户服务的方式有三种:

1.每来一个客户就为其创建一个线程;

2.创建一个线程池,在线程中accept;

3.创建一个线程池,在main中accept;

对于第一种:

int  main(int argc, char const *argv[]){int listenfd,connfd;void sig_int(int);void *doit(void *);pthread_t tid;socklen_t clilen,addrlen;struct sockaddr *cliaddr;listenfd = /*创建一个监听套接字*/cliaddr = malloc(addrlen);signal(SIGINT,sig_int);for(;;){connfd = accept(listenfd,cliaddr,&clilen);pthread_create(&tid,NULL,&doit,(void *) connfd);}return 0;}void *doit(void *arg){void web_child(int);pthread_detach(pthread_self());web_child((int) arg);//对套接字进行处理close((int) arg);return NULL:}

对于第二种:

typedef struct {pthread_t thread_tid;long thread_count;}THread;THread *tptr;int listenfd,nthreads;socklen_t addrlen;pthread_mutex_t mlock;int main(int argc, char const *argv[]){int i;void sig_int(int,thread_make(int));listenfd = tcp_listen(/**/);nthreads = atoi(argv[argc-1]);tptr = calloc(nthreads,sizeof(THread));//一共nthreads个线程,线程信息用结构体数组来保存for(i=0;i<nthreads;i++)thread_make(i);//提前创建一个线程池signal(SIGINT,sig_int);for(;;)pause();}void thread_make(int i){void *thread_main(void *);pthread_create(&tptr[i].thread_tid,NULL,&thread_main,(void *) i);return;}void *thread_main(void *arg){     int connfd;    void web_child(int);    socklen_t clilen;    struct sockaddr *cliaddr;    cliaddr = malloc(addrlen);    for(;;)    {    clilen = addrlen;    /*先抢到锁的线程,先accept,这样保证每次只有一个线程处理新到来的连接;    这里不用互斥锁也是可以的,但是每个线程都会阻塞在accept中,当有一个客户到来时,就会引发惊群问题(所有线程被唤醒,但只有一个线程为客户服务)*/    pthread_mutex_lock(&mlock);    connfd = accept(listenfd,cliaddr,&clilen);    pthread_mutex_unlock(&mlock);    tptr[(int) arg].thread_count++;    web_child(connfd);    close(connfd);    }}

对于第三种:


typedef struct {pthread_t thread_tid;long thread_count;}THread;THread *tptr;#define MAXNCLI 32int clifd[MAXNCLI] ,iget ,iput;pthread_mutex_t clifd_mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t clifd_cond = PTHREAD_COND_INITIALIZER;static int nthreads;int main(int argc, char const *argv[]){int i;int connfd;socklen_t clilen;struct sockaddr *cliaddr;void sig_int(int,thread_make(int));listenfd = tcp_listen(/**/);nthreads = atoi(argv[argc-1]);cliaddr = malloc(addrlen);tptr = calloc(nthreads,sizeof(THread));//一共nthreads个线程,线程信息用结构体数组来保存    iget=iput=0;for(i=0;i<nthreads;i++)thread_make(i);//提前创建一个线程池signal(SIGINT,sig_int);for(;;){clilen = addrlen;connfd = accept(listenfd,cliaddr,&clilen);//在main里accept,然后把accept返回的套接字保存起来,分配一个线程为其服务pthread_mutex_lock(&clifd_mutex);clifd[iput] = connfd;if(++iput == MAXNCLI)iput = 0;pthread_cond_signal(&clifd_cond);pthread_mutex_unlock(&clifd_mutex);}}void thread_make(int i){void *thread_main(void *);pthread_create(&tptr[i].thread_tid,NULL,&thread_main,(void *) i);return;}void *thread_main(void *arg){     int connfd;    void web_child(int);        for(;;)    {    pthread_mutex_lock(&clifd_mutex);    while(iget == iput)    pthread_cond_wait(&clifd_cond,&clifd_mutex);//进入pthread_cond_wait,就会释放clifd_mutex,返回就重新加锁    connfd = clifd[iget];    if(++iget == MAXNCLI)    iget = 0;    pthread_mutex_unlock(&clifd_mutex);    tptr[(int) arg].thread_count++;    web_child(connfd);    close(connfd);    }}



0 0