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

设计一个线程池,大小为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;
}

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 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;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值