线程池服务程序设计(续)

来源:互联网 发布:大数据行业分析 编辑:程序博客网 时间:2024/06/05 21:56

设计一个线程池,大小为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  4typedef 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 threadpoolvoid cleanthreadpool(){int i;for(i = 0; i < MAX_NUM; i++){threadpoolatom[i].clientsocket = 0;threadpoolatom[i].flag = 0;threadid[i] = 0;}}//show the thread statusvoid 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 waitif(threadpoolatom[index].flag){if (flg == 1){printf("Processthread %d connect and keep connecting!\n",index);flg = 0;}char buffer[1024];int iDataNum ;//recive--iniDataNum = 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--outint 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 socketif((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_initcleanthreadpool();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);elseprintf("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 queuethreadpoolatom[i].clientsocket = clientsocket;break;}}printf("now thread pool status:\n");showthreadstatus();}close(serverSocket);return 0;}

client端:

#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 5555int pool_add_worker (void *(*processthread) (void *), void *);void *thread_routine (void *arg);//thread functionvoid *processthread(void *sock);//deal with the client message//share resourcestatic 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;}