对服务器来说,以线程为客户服务的方式有三种:
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 32
int 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);
}
}