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