设计一个线程池,大小为4,服务器的功能就是“加减乘除”,客户端只需输入相应的指令和两个数字,比如输入add,然后输入12,13,然后把相应的结构传送给服务器计算,服务器把结果传回。代码来自《LinuxC程序基础与实例讲解》中,只是做了部分修改:
server端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <errno.h> #include <netdb.h> #include <net/if.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <signal.h> #define SERVER_PORT 5555 #define MAX_NUM 4 typedef struct mathopt { int oprate; float value1; float value2; }mopt; //every thread has this data structure typedef struct threadatom { int clientsocket; //标记可用套接字,only flag = 1,the socket can be used int flag;// 标记flag值:1 means the thread is in the working status and 0 means waiting }tatom; struct threadatom threadpoolatom[MAX_NUM]; //threadpool array pthread_t threadid[MAX_NUM]; //clean the threadpool void cleanthreadpool() { int i; for(i = 0; i < MAX_NUM; i++) { threadpoolatom[i].clientsocket = 0; threadpoolatom[i].flag = 0; threadid[i] = 0; } } //show the thread status void showthreadstatus() { int i; for( i = 0; i < MAX_NUM; i++) { // printf("i = %d:threadid [%d],clientsocket [%d],flag [%s] \n",i,threadid[i],threadpoolatom[i].clientsocket,threadpoolatom[i].flag>=1?"working":"waiting"); printf("i = %d:threadid [%d],clientsocket [%d],flag [%s] \n",i,i,threadpoolatom[i].clientsocket,threadpoolatom[i].flag>=1?"working":"waiting"); } } void* processthread(void *para) { // int index = *((int *)para); static int flg = 1; int index = (int)para; struct threadatom *pthread = &threadpoolatom[index]; printf("Entery the processthread %d and waiting\n",index); while(1) { //the flag means the working status,if 1,then make it work,else make it wait if(threadpoolatom[index].flag) { if (flg == 1) { printf("Processthread %d connect and keep connecting!\n",index); flg = 0; } char buffer[1024]; int iDataNum ; //recive--in iDataNum = recv(pthread->clientsocket,buffer,1024,0); int length = sizeof(struct mathopt); if(iDataNum < length) { perror("error: Recv data !!!"); pthread->clientsocket = 0; pthread->flag = 0; continue ; } struct mathopt *pMp = (struct mathopt *)buffer; float result = 0; if(pMp->oprate == 0) { result = pMp->value1 + pMp->value2; } else if(pMp->oprate == 1) { result = pMp->value1 - pMp->value2; } else if(pMp->oprate == 2) { result = pMp->value1 * pMp->value2; } else if(pMp->oprate == 3) { result = pMp->value1 / pMp->value2; } else if(pMp->oprate == 4) { pthread->clientsocket = 0; pthread->flag = 0; printf("Processthread %d disconnect!\n",index); continue; } char buf[100]; sprintf(buf,"%f",result); printf("v1:%f v2:%f o:%d r:%f task[%d] finished!\n",pMp->value1,pMp->value2,pMp->oprate,result,index); //send--out int error = send(pthread->clientsocket,buf,sizeof(buf),0); if(error < 0) { close(pthread->clientsocket); pthread->clientsocket = 0; pthread->flag = 0; continue; } } else { // printf("sleep thread :%d\n",index); sleep(1) ; } } } int main(int argc, char const *argv[]) { int serverSocket; struct sockaddr_in server_addr; struct sockaddr_in clientAddr; int addr_len = sizeof(clientAddr); //create server socket if((serverSocket = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror( "error: create server socket!!!"); exit(EXIT_FAILURE); } //design the server address bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family =AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind the server socket if(bind(serverSocket,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) { perror("error: bind address !!!!"); exit(EXIT_FAILURE); } //listen the server socket if(listen(serverSocket,5)<0) { perror("error: listen !!!!"); exit(EXIT_FAILURE); } // all above server express socket_init cleanthreadpool(); int i; for( i = 0 ; i < MAX_NUM; i++) { pthread_t temp; int err; printf("i = %d\n",i); // err = pthread_create(&temp, NULL, processthread, (void *)&i); //create thread err = pthread_create(&temp, NULL, processthread, (void *)i); if(err == 0) printf("thread[%d] start ok............\n",i); else printf("thread[%d] create failed\n",i); sleep(2); } printf("init threadpool status:\n"); showthreadstatus(); while(1) { int clientsocket; printf("accetp conn.....\n"); clientsocket = accept(serverSocket,(struct sockaddr *)&clientAddr,(socklen_t*)&addr_len); if(clientsocket < 0) { perror("error: accept client socket !!!"); continue; } printf("find pool.....\n"); for( i = 0 ; i < MAX_NUM; i++) { if(threadpoolatom[i].flag == 0) { threadpoolatom[i].flag = 1; //fetch a socket from the finished listen queue threadpoolatom[i].clientsocket = clientsocket; break; } } printf("now thread pool status:\n"); showthreadstatus(); } close(serverSocket); return 0; }
#include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #define PORT 5555 #define SERVER_IP "127.0.0.1" typedef struct mathopt { int oprate; float value1; float value2; }mopt; void createopt(struct mathopt *pMp) { printf("please input operand one:"); scanf("%f",&(pMp->value1)); printf("please input operand two:"); scanf("%f",&(pMp->value2)); } void help() { printf("==================================================================\n"); printf("version:V1.0\n"); printf("author:my2005lb\n\n\n"); printf("%-12s %-12s\n","Command","Fuction"); printf("%-12s %-12s\n","add","Adder computing"); printf("%-12s %-12s\n","minus","Minus computing"); printf("%-12s %-12s\n","multiply","Multiply computing"); printf("%-12s %-12s\n","divide","Divide computing"); printf("%-12s %-12s\n","help","Print help information"); printf("%-12s %-12s\n","quit","Exit the program"); printf("==================================================================\n"); } int main(int argc, char const *argv[]) { struct sockaddr_in serverAddr; int clientSocket; char sendbuf[200]; char recvbuf[200]; char command[20]; if((clientSocket=socket(AF_INET,SOCK_STREAM,0)) < 0) { perror( "error: create socket!!!"); return -1; } serverAddr.sin_family=AF_INET; serverAddr.sin_port=htons(PORT); serverAddr.sin_addr.s_addr=inet_addr(SERVER_IP); if(connect(clientSocket,( struct sockaddr * )&serverAddr,sizeof(serverAddr)) < 0) { perror("error: connect remote server !!!"); exit(1); } printf("infor: connect with destination host........[ok]\n"); while(1) { printf("Input your World:>"); scanf("%s",command); struct mathopt mp; if(strcmp(command,"add") == 0) { createopt(&mp); mp.oprate = 0; } else if(strcmp(command,"minus") == 0) { createopt(&mp); mp.oprate = 1; } else if(strcmp(command,"multiply") == 0) { createopt(&mp); mp.oprate = 2; } else if(strcmp(command,"divide") == 0) { while(1) { createopt(&mp); if(mp.value2 == 0) { printf("warning: Dividend can not be 0!!!!!\n"); } else { break; } } mp.oprate = 3; } else if(strcmp(command,"help") == 0) { help(); continue ; } else if(strcmp(command,"quit") == 0) { mp.oprate = 4; } else { printf("error: can't identify your input !!!\n"); continue ; } send(clientSocket,(char *)&mp,sizeof(mp),0); if(mp.oprate == 4) { break; } recv(clientSocket,recvbuf,200,0); printf("the result is: %s\n",recvbuf); } close(clientSocket); return 0; }
有个问题:就是我只能四个客户端同时用,如果有第五个客户端联接进来,只能等待,但是当前4个客户端退出一个以后,我第五个客户端还是不能用这个退出的线程。所以代码有待改进!
服务端程序的一些改进:
参见http://blog.csdn.net/hubi0952/article/details/8045094
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <errno.h> #include <netdb.h> #include <net/if.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <signal.h> #include <assert.h> /* *线程池里所有运行和等待的任务都是一个CThread_worker *由于所有任务都在链表里,所以是一个链表结构 */ typedef struct worker { /*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/ void *(*processthread)(void *sock); /*回调函数的参数*/ void *sock; struct worker *next; } CThread_worker; typedef struct mathopt { int oprate; float value1; float value2; }mopt; typedef struct threadatom { int clientsocket; //标记可用套接字,only flag = 1,the socket can be used int flag;// 标记flag值:1 means the thread is in the working status and 0 means waiting }tatom; /*线程池结构*/ typedef struct { pthread_mutex_t queue_lock; pthread_cond_t queue_ready; /*链表结构,线程池中所有等待任务*/ CThread_worker *queue_head; /*是否销毁线程池*/ int shutdown; pthread_t *threadid; /*线程池中允许的活动线程数目*/ int max_thread_num; /*当前等待队列的任务数目*/ int cur_queue_size; } CThread_pool; #define SERVER_PORT 5555 int pool_add_worker (void *(*processthread) (void *), void *); void *thread_routine (void *arg);//thread function void *processthread(void *sock);//deal with the client message //share resource static CThread_pool *pool = NULL; void pool_init (int max_thread_num) { pool = (CThread_pool *) malloc (sizeof (CThread_pool)); pthread_mutex_init (&(pool->queue_lock), NULL); pthread_cond_init (&(pool->queue_ready), NULL); pool->queue_head = NULL; pool->max_thread_num = max_thread_num; pool->cur_queue_size = 0; pool->shutdown = 0; pool->threadid = (pthread_t *) malloc (max_thread_num * sizeof (pthread_t)); int i; for (i = 0; i < max_thread_num; i++) { pthread_create (&(pool->threadid[i]), NULL, thread_routine, NULL); } } void *thread_routine (void *arg) { printf ("starting thread 0x%x\n", pthread_self ()); while (1) { pthread_mutex_lock (&(pool->queue_lock)); /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意 pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/ while (pool->cur_queue_size == 0 && !pool->shutdown) { printf ("thread 0x%x is waiting\n", pthread_self ()); pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock)); } /*线程池要销毁了*/ if (pool->shutdown) { /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/ pthread_mutex_unlock (&(pool->queue_lock)); printf ("thread 0x%x will exit\n", pthread_self ()); pthread_exit (NULL); } printf ("thread 0x%x is starting to work\n", pthread_self ()); /*assert是调试的好帮手*/ assert (pool->cur_queue_size != 0); assert (pool->queue_head != NULL); /*等待队列长度减去1,并取出链表中的头元素*/ pool->cur_queue_size--; CThread_worker *worker = pool->queue_head; pool->queue_head = worker->next; pthread_mutex_unlock (&(pool->queue_lock)); /*调用回调函数,执行任务*/ (*(worker->processthread)) (worker->sock); free (worker); worker = NULL; } /*这一句应该是不可达的*/ pthread_exit (NULL); } void* processthread(void *sock) { int clientsocket = *(int *)sock; printf("Entery the processthread and waiting\n"); while(1) { char buffer[1024]; int iDataNum ; //recive--in iDataNum = recv(clientsocket,buffer,1024,0); int length = sizeof(struct mathopt); if(iDataNum < length) { perror("error: Recv data !!!"); continue ; } struct mathopt *pMp = (struct mathopt *)buffer; float result = 0; if(pMp->oprate == 0) { result = pMp->value1 + pMp->value2; } else if(pMp->oprate == 1) { result = pMp->value1 - pMp->value2; } else if(pMp->oprate == 2) { result = pMp->value1 * pMp->value2; } else if(pMp->oprate == 3) { result = pMp->value1 / pMp->value2; } else if(pMp->oprate == 4) { printf("Processthread %d disconnect!\n",clientsocket); // continue; break; } char buf[100]; sprintf(buf,"%f",result); printf("v1:%f v2:%f o:%d r:%f task[%d] finished!\n",pMp->value1,pMp->value2,pMp->oprate,result,clientsocket); //send--out int error = send(clientsocket,buf,sizeof(buf),0); if(error < 0) { close(clientsocket); // continue; break; } } sleep(1) ; } /*向线程池中加入任务*/ int pool_add_worker (void *(*process) (void *sock), void *sock) { /*构造一个新任务*/ CThread_worker *newworker = (CThread_worker *) malloc (sizeof (CThread_worker)); newworker->processthread = processthread; newworker->sock = (int *)sock; newworker->next = NULL;/*别忘置空*/ pthread_mutex_lock (&(pool->queue_lock)); /*将任务加入到等待队列中*/ CThread_worker *member = pool->queue_head; if (member != NULL) { while (member->next != NULL) member = member->next; member->next = newworker; } else { pool->queue_head = newworker; } assert (pool->queue_head != NULL); pool->cur_queue_size++; pthread_mutex_unlock (&(pool->queue_lock)); /*好了,等待队列中有任务了,唤醒一个等待线程; 注意如果所有线程都在忙碌,这句没有任何作用*/ pthread_cond_signal (&(pool->queue_ready)); return 0; } /*销毁线程池,等待队列中的任务不会再被执行,但是正在运行的线程会一直 把任务运行完后再退出*/ int pool_destroy () { if (pool->shutdown) return -1;/*防止两次调用*/ pool->shutdown = 1; /*唤醒所有等待线程,线程池要销毁了*/ pthread_cond_broadcast (&(pool->queue_ready)); /*阻塞等待线程退出,否则就成僵尸了*/ int i; for (i = 0; i < pool->max_thread_num; i++) pthread_join (pool->threadid[i], NULL); free (pool->threadid); /*销毁等待队列*/ CThread_worker *head = NULL; while (pool->queue_head != NULL) { head = pool->queue_head; pool->queue_head = pool->queue_head->next; free (head); } /*条件变量和互斥量也别忘了销毁*/ pthread_mutex_destroy(&(pool->queue_lock)); pthread_cond_destroy(&(pool->queue_ready)); free (pool); /*销毁后指针置空是个好习惯*/ pool=NULL; return 0; } int main (int argc, char **argv) { //socket init int serverSocket; int clientsocket; struct sockaddr_in client_addr; struct sockaddr_in server_addr; int addr_len = sizeof(client_addr); //create the server socket if ((serverSocket = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("socket create failed !"); exit(EXIT_FAILURE); } //design the server address bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind the server socket if (bind(serverSocket,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) { perror("bind the server socket failed!"); exit(EXIT_FAILURE); } //listen the server socket if (listen(serverSocket,5) < 0) { perror("listen server socket failed!"); exit(EXIT_FAILURE); } pool_init (3);/*线程池中最多三个活动线程*/ while(1) { clientsocket = accept(serverSocket,(struct sockaddr *)&client_addr,(socklen_t *)&addr_len); if (clientsocket < 0) { perror("clientsocket accept failed!"); continue; } pool_add_worker (processthread, &clientsocket); } /*等待所有任务完成*/ sleep (5); /*销毁线程池*/ pool_destroy (); return 0; }