【原创】TCP Socket 简单练习 --- 线程池实现并发服务器 分类: ...


【原创】TCP Socket 简单练习 --- 线程池实现并发服务器


服务器函数执行流程

main

init_system

creat_pthread_pool

child_work


thread_manager


task_manager

process_client


monitor


sys_clean


Makefile文件

CC = gcc
TARGET = pthread_pool
SRC = pthread_pool.c base.c
OBJECT = pthread_pool.o  base.o
INCLUDES = -I./
LDFLAGS = -lpthread

all:$(TARGET)

$(OBJECT):$(SRC)
	$(CC) -c $(INCLUDES) ${SRC}

$(TARGET):$(OBJECT)
	$(CC) -o $@ $(OBJECT) $(LDFLAGS)

.PHONY:clean

clean:
	@rm -rf $(OBJECT) $(TARGET) *~

服务器代码

头文件

#ifndef __PTHREAD_POOL_H__

#define __PTHREAD_POOL_H__

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <errno.h>

#define THREAD_MAX_NUM	100     /* max number of thread. */
#define THREAD_DEF_NUM	20      /* by default ,number of thread. */
#define THREAD_MIN_NUM	5       /* min number of thread pool. */
#define LISNUM<span style="white-space:pre">	</span>5
#define PORT	9001
#define MAXBUF	1024


/*
 * *ds of the every task. make all task in a single link
 */
//任务结构节点,用于描述每个任务的具体属性
typedef struct task_node
{
	void *arg;                              /* fun arg. */
	void *(*fun)(void *);                   /* the real work of the task. */
	pthread_t		tid;            /* which thread exec this task. */
	int			work_id;        /* task id. */
	int			flag;           /* 1: assigned, 0: unassigned. */
	struct task_node	*next;
	pthread_mutex_t		mutex;          /* when modify this ds and exec the work,lock the task ds. */
} TASK_NODE;


/*
 * *the ds  of the task_queue
 */
//任务队列结构,用于控制整个任务队列
typedef struct task_queue
{
	pthread_mutex_t		mutex;
	pthread_cond_t		cond;   /* when no task, the manager thread wait for ;when a new task come, signal. */
	struct task_node	*head;  /* point to the task_link. */
	int			number; /* current number of task, include unassinged and assigned but no finished. */
} TASK_QUEUE_T;


/*
 * *the ds of every thread, make all thread in a double link queue.
 */
//线程结构节点,用于描述每个线程的具体属性
typedef struct pthread_node
{
	pthread_t		tid;    /* the pid of this thread in kernel,the value is  syscall return . */
	int			flag;   /*  1:busy, 0:free. */
	struct task_node	*work;  /*  if exec a work, which work. */
	struct pthread_node	*next;
	struct pthread_node	*prev;
	pthread_cond_t		cond;   /* when assigned a task, signal this child thread by manager. */
	pthread_mutex_t		mutex;
} THREAD_NODE;


/*
 * *the ds of the thread queue
 */
//线程队列结构,用于控制空闲线程队列和忙碌线程队列
typedef struct pthread_queue
{
	int			number; /* the number of thread in this queue. */
	struct pthread_node	*head;
	struct pthread_node	*rear;
	pthread_cond_t		cond;   /* when no idle thread, the manager wait for ,or when a thread return with idle, signal. */
	pthread_mutex_t		mutex;
} PTHREAD_QUEUE_T;

//在pthread_poll()中定义的三个结构的指针
extern PTHREAD_QUEUE_T	*pthread_queue_idle;    /* the idle thread double link queue. */
extern PTHREAD_QUEUE_T	*pthread_queue_busy;    /* the work thread double link queue. */
extern TASK_QUEUE_T	*task_queue_head;       /* the task queuee single link list. */

void *child_work( void *ptr );

void create_pthread_pool( void );

void init_system( void );

void *thread_manager( void *ptr );

void *prcoess_client( void *ptr );

void *task_manager( void *ptr );

void *monitor( void *ptr );

void sys_clean( void );

#endif

基础函数

#include "pthread_pool.h"


/*
 * *child_work:the code exec in child thread
 * *ptr: the ds of thread_node of current thread.
 * *return :nothing.void * just avoid warning.
 */
/*
	child_work为创建的线程执行的函数
	主要用来等待线程属性状态的变化,来判断是否有任务要执行
	并且判断线程的工作状态的变化,来决定加入哪个线程队列(空闲还是忙碌)
*/
void *
child_work( void *ptr )
{
	//这里的ptr为(void *) &temp[i]
	THREAD_NODE * self = (THREAD_NODE *) ptr;

	/*modify the tid attribute the first time exec */
	pthread_mutex_lock( &self->mutex );
	self->tid = syscall( SYS_gettid );//获得线程自身id
	pthread_mutex_unlock( &self->mutex );

	while ( 1 )
	{
		pthread_mutex_lock( &self->mutex );

		/*if no task exec,blocked */
		/* 
			关键的一句话
			从线程的属性struct task_node *work(即为self->work)
			判断是否已给当前线程分配任务
		*/
		//如果该线程尚没有分配任务,则通过条件变量阻塞等待条件变量self->cond
		if ( NULL == self->work ) 
		{
			pthread_cond_wait( &self->cond, &self->mutex );
		}

		pthread_mutex_lock( &self->work->mutex );

		/*execute the real work. 
			开始执行任务
		*/
		self->work->fun( self->work->arg );

		/*after finished the work 
			任务执行完后,撤销任务的属性,并销毁任务本身,释放其占用的资源
		*/
		self->work->fun		= NULL;
		self->work->flag	= 0;
		self->work->tid		= 0;
		self->work->next	= NULL;

		free( self->work->arg );

		pthread_mutex_unlock( &self->work->mutex ); /* unlock the task */
		pthread_mutex_destroy( &self->work->mutex );

		/*free the task space */
		free( self->work );

		/*make self thread no work */
		self->work	= NULL;
		self->flag	= 0;


		/*
		 * *get new task from the task_link if not NULL.
		 * *there no idle thread if there are task to do.
		 * *if on task ,make self idle and add to the idle queue.
		 */
		/*
			执行完上一个任务后,查看任务队列中是否还有任务		
		*/
		pthread_mutex_lock( &task_queue_head->mutex );
		if ( task_queue_head->head != NULL )//如果有任务,则分配任务
		{
			TASK_NODE * temp = task_queue_head->head;

			/*get the first task */
			task_queue_head->head = task_queue_head->head->next;

			/*modify self thread attribute */
			self->flag	= 1;
			self->work	= temp;
			temp->tid	= self->tid;
			temp->next	= NULL;
			temp->flag	= 1;

			task_queue_head->number--;

			pthread_mutex_unlock( &task_queue_head->mutex );

			pthread_mutex_unlock( &self->mutex );

			continue;
		}
		else //如果没有任务,从忙碌线程队列中删除此线程,将其加入空闲线程队列中  
		{
			/*no task need to exec, add self to idle queue and del from busy queue */
			pthread_mutex_unlock( &task_queue_head->mutex );

			pthread_mutex_lock( &pthread_queue_busy->mutex );

			/*self is the last execte thread 
				如果此线程是忙碌的线程队列中的仅剩的一个线程
			*/
			if ( pthread_queue_busy->head == self
			     && pthread_queue_busy->rear == self )
			{
				pthread_queue_busy->head	= pthread_queue_busy->rear = NULL;
				self->next			= self->prev = NULL;
			}
			/*the first one thread in busy queue 
				如果此线程是忙碌的线程队列中的第一个线程
			*/
			else if ( pthread_queue_busy->head == self
				  && pthread_queue_busy->rear != self )
			{
				pthread_queue_busy->head	= pthread_queue_busy->head->next;
				pthread_queue_busy->head->prev	= NULL;

				self->next = self->prev = NULL;
			}
			/*the last one thread in busy queue 
				如果此线程是忙碌的线程队列中的末尾的一个线程
			*/
			else if ( pthread_queue_busy->head != self
				  && pthread_queue_busy->rear == self )
			{
				pthread_queue_busy->rear	= pthread_queue_busy->rear->prev;
				pthread_queue_busy->rear->next	= NULL;

				self->next = self->prev = NULL;
			}
			/*middle one 
				如果此线程是忙碌的线程队列中的中间的某个线程
			*/
			else{
				self->next->prev	= self->prev;
				self->prev->next	= self->next;
				self->next		= self->prev = NULL;
			}

			pthread_mutex_unlock( &pthread_queue_busy->mutex );

			/*add self to the idle queue 
				将此线程加入空闲线程队列中
			*/
			pthread_mutex_lock( &pthread_queue_idle->mutex );

			/*now the idle queue is empty 
				判断空闲线程队列的情况,根据不同的情况将此线程加入不同的位置
			*/
			if ( pthread_queue_idle->head == NULL
			     || pthread_queue_idle->rear == NULL )
			{
				pthread_queue_idle->head	= pthread_queue_idle->rear = self;
				self->next			= self->prev = NULL;
			}else  {
				self->next		= pthread_queue_idle->head;
				self->prev		= NULL;
				self->next->prev	= self;

				pthread_queue_idle->head = self;
				pthread_queue_idle->number++;
			}

			pthread_mutex_unlock( &pthread_queue_idle->mutex );

			pthread_mutex_unlock( &self->mutex );

			/*signal have idle thread 
				告知阻塞等待条件变量pthread_queue_idle->cond的位置已有空闲线程
			*/
			pthread_cond_signal( &pthread_queue_idle->cond );
		}
	}
}


/*
 * *create thread pool when the system on, and thread number is THREAD_DEF_NUM.
 * *when init, initial all the thread into a double link queue and all wait fo self->cond.
 */
void
create_pthread_pool( void )
{
	//分配线程节点
	THREAD_NODE * temp =
		(THREAD_NODE *) malloc( sizeof(THREAD_NODE) * THREAD_DEF_NUM );

	if ( temp == NULL )
	{
		printf( " malloc failure\n" );
		exit( EXIT_FAILURE );
	}

	/*init as a double link queue 
		初始化为双向链式队列
	*/
	int i;

	//THREAD_DEF_NUM为线程池中线程的最大数量
	//for循环开始创建线程池
	for ( i = 0; i < THREAD_DEF_NUM; i++ )
	{
		temp[i].tid		= i + 1;
		temp[i].work	= NULL;
		temp[i].flag	= 0;

		if ( i == THREAD_DEF_NUM - 1 )
			temp[i].next = NULL;

		if ( i == 0 )
			temp[i].prev = NULL;

		//双向链表的体现
		temp[i].prev	= &temp[i - 1];
		temp[i].next	= &temp[i + 1];

		pthread_cond_init( &temp[i].cond, NULL );
		pthread_mutex_init( &temp[i].mutex, NULL );

		/*create this thread 
			在此创建线程,各个线程执行的函数为child_work
		*/
		pthread_create( &temp[i].tid, NULL, child_work, (void *) &temp[i] );
	}

	/*modify the idle thread queue attribute 
		修改空闲线程队列的属性
	*/
	pthread_mutex_lock( &pthread_queue_idle->mutex );

	pthread_queue_idle->number	= THREAD_DEF_NUM;
	//此句就将刚创建的那些线程给空闲线程队列
	pthread_queue_idle->head	= &temp[0];
	pthread_queue_idle->rear	= &temp[THREAD_DEF_NUM - 1];

	pthread_mutex_unlock( &pthread_queue_idle->mutex );
}


/*
 * *init_system :init the system glob pointor.
 */
void
init_system( void )
{
	/*init the pthread_queue_idle 
		初始化空闲线程队列,采用的是普通的双向链式结构(未循环)
	*/
	pthread_queue_idle =
		(PTHREAD_QUEUE_T *) malloc( sizeof(PTHREAD_QUEUE_T) );

	pthread_queue_idle->number	= 0;
	pthread_queue_idle->head	= NULL;
	pthread_queue_idle->rear	= NULL;
	pthread_mutex_init( &pthread_queue_idle->mutex, NULL );
	pthread_cond_init( &pthread_queue_idle->cond, NULL );

	/*init the pthread_queue_busy 
		初始化空闲线程队列,采用的是普通的双向链式结构(未循环)
	*/
	pthread_queue_busy =
		(PTHREAD_QUEUE_T *) malloc( sizeof(PTHREAD_QUEUE_T) );

	pthread_queue_busy->number	= 0;
	pthread_queue_busy->head	= NULL;
	pthread_queue_busy->rear	= NULL;
	pthread_mutex_init( &pthread_queue_busy->mutex, NULL );
	pthread_cond_init( &pthread_queue_busy->cond, NULL );

	/*init the task_queue_head 
		初始化任务队列,采用单向链表
	*/
	task_queue_head = (TASK_QUEUE_T *) malloc( sizeof(TASK_QUEUE_T) );

	task_queue_head->head	= NULL;
	task_queue_head->number = 0;
	pthread_cond_init( &task_queue_head->cond, NULL );
	pthread_mutex_init( &task_queue_head->mutex, NULL );

	/*create thread poll 
		创建线程池
	*/
	create_pthread_pool();
}


/*
 * *thread_manager:code exec in manager thread.
 *               block on task_queue_head->cond when no task come.
 *               block on pthread_queue_idle->cond when no idle thread
 **ptr:no used ,in order to avoid warning.
 **return :nothing.
 */

void *
thread_manager( void *ptr )
{
	while ( 1 )
	{
		THREAD_NODE	* temp_thread	= NULL;
		TASK_NODE	* temp_task	= NULL;

		/*
		 * *get a new task, and modify the task_queue.
		 * *if no task block om task_queue_head->cond.
		 */
		pthread_mutex_lock( &task_queue_head->mutex );
		//如果任务队列为空,则阻塞等待条件变量task_queue_head->cond
		if ( task_queue_head->number == 0 )
			pthread_cond_wait( &task_queue_head->cond,
					   &task_queue_head->mutex );

		//如果不为空,则开始准备分配任务,并修改任务队列属性
		temp_task		= task_queue_head->head;
		task_queue_head->head	= task_queue_head->head->next;
		task_queue_head->number--;

		pthread_mutex_unlock( &task_queue_head->mutex );


		/*
		 * *get a new idle thread, and modify the idle_queue.
		 * *if no idle thread, block on pthread_queue_idle->cond.
		 */
		//有了任务之后,开始判断是否有空闲线程
		pthread_mutex_lock( &pthread_queue_idle->mutex );
		
		//如果没有空闲线程,则阻塞等待条件变量pthread_queue_idle->cond
		if ( pthread_queue_idle->number == 0 )
			pthread_cond_wait( &pthread_queue_idle->cond,
					   &pthread_queue_idle->mutex );
					   
		//如果有空闲线程则取出一个空闲线程,然后修改空闲线程队列属性
		temp_thread = pthread_queue_idle->head;

		/*if this is the last idle thread ,modiry the head and rear pointor */
		if ( pthread_queue_idle->head == pthread_queue_idle->rear )
		{
			pthread_queue_idle->head	= NULL;
			pthread_queue_idle->rear	= NULL;
		}
		/*if idle thread number>2, get the first one,modify the head pointor  */
		else{
			pthread_queue_idle->head	= pthread_queue_idle->head->next;
			pthread_queue_idle->head->prev	= NULL;
		}

		pthread_queue_idle->number--;//将空闲线程队列数量减一

		pthread_mutex_unlock( &pthread_queue_idle->mutex );

		/*modify the  task attribute. 
			修改取出的线程的线程结构属性和相关的任务结构属性
		*/
		pthread_mutex_lock( &temp_task->mutex );

		temp_task->tid	= temp_thread->tid;
		temp_task->next = NULL;
		temp_task->flag = 1;

		pthread_mutex_unlock( &temp_task->mutex );

		/*modify the idle thread attribute. */
		pthread_mutex_lock( &temp_thread->mutex );

		temp_thread->flag	= 1;
		temp_thread->work	= temp_task;
		temp_thread->next	= NULL;
		temp_thread->prev	= NULL;

		pthread_mutex_unlock( &temp_thread->mutex );

		/*add the thread assinged task to the busy queue. */
		//将已分配任务的线程加入忙碌线程队列中
		pthread_mutex_lock( &pthread_queue_busy->mutex );

		/*if this is the first one in busy queue */
		if ( pthread_queue_busy->head == NULL )
		{
			pthread_queue_busy->head	= temp_thread;
			pthread_queue_busy->rear	= temp_thread;
			temp_thread->prev		= temp_thread->next = NULL;
		}else  {
			/*insert in thre front of the queue */
			pthread_queue_busy->head->prev	= temp_thread;
			temp_thread->prev		= NULL;
			temp_thread->next		= pthread_queue_busy->head;
			pthread_queue_busy->head	= temp_thread;
			pthread_queue_busy->number++;
		}
		pthread_mutex_unlock( &pthread_queue_busy->mutex );

		/*signal the child thread to exec the work */
		//告知阻塞等待条件变量temp_thread->cond的位置,开始执行任务
		pthread_cond_signal( &temp_thread->cond );
	}
}


/*
 * *code to process the new client in every chilld pthead.
 * *ptr: the fd come from listen thread that can communicate to the client.
 * *return:nothing. void * only used to avoid waring.
 */
//用来处理任务的函数
void *
prcoess_client( void *ptr )
{
	int net_fd;
	net_fd = atoi( (char *) ptr );

	socklen_t	len;
	char		buf[MAXBUF + 1];
	/*下面是select用到的变量的定义 */
	fd_set		rfds;
	struct timeval	tv;
	int		retval;
	int		maxfd = -1;

	while ( 1 )
	{
		FD_ZERO( &rfds );                                                       /* 初始化rfds为空 */
		FD_SET( 0, &rfds );                                                     /* 将标准输入的描述符0加入到集合rfds中 */
		FD_SET( net_fd, &rfds );                                                /* 将net_fd加入到集合rfds中 */
		maxfd		= net_fd + 1;
		tv.tv_sec	= 1;                                                    /* 阻塞等待时间为1s */
		tv.tv_usec	= 0;

		retval = select( maxfd, &rfds, NULL, NULL, &tv );                       /* 多路复用,同时监测描述符0和net_fd */
		if ( retval == -1 )                                                     /* select函数执行出错 */
		{
			perror( "select" );
			exit( EXIT_FAILURE );
		}else if ( retval == 0 )                                                /* select函数执行超时 */
			continue;
		else{ /*有描述符引起异常 */
			if ( FD_ISSET( 0, &rfds ) )                                     /* 判断是不是标准输入0引起的异常 */
			{
				bzero( buf, sizeof(buf) );                              /* 清空buf */
				fgets( buf, sizeof(buf) - 1, stdin );                   /* 从终端接收输入 */

				if ( !strncasecmp( buf, "quit", 4 ) )                   /* 判断是否为退出 */
				{
					printf( "i will close the connect!\n" );
					close( net_fd );
					goto clean;
				}

				len = send( net_fd, buf, strlen( buf ) - 1, 0 );        /* 向客户端发送消息 */
				if ( len > 0 )
				{
					printf( "send successful,%d byte send!\n", len );
				}else  {
					printf( "message '%s' send failure !\n", buf );
					printf( "errno code is %d, errno message is '%s'\n", errno, strerror( errno ) );
					close( net_fd );
					goto clean;
				}
			}

			if ( FD_ISSET( net_fd, &rfds ) )                        /* 判断是不是net_fd引起的异常 */
			{
				bzero( buf, sizeof(buf) );
				len = recv( net_fd, buf, sizeof(buf) - 1, 0 );  /* 从客户端接收消息 */
				if ( len > 0 )
					printf( "message recv successful : '%s', %d Byte recv\n", buf, len );
				else if ( len < 0 )
				{
					printf( "recv failure !\nerrno code is %d, errno message is '%s'\n", errno, strerror( errno ) );
					close( net_fd );
					goto clean;
				}else  { /* 如果客户端已关闭 */
					printf( "the other one close quit\n" );
					close( net_fd );
					return;
				}
			}
		}
	}
	close( net_fd );
	return;

clean:
	sys_clean();
}


/*
 * *task_manager: get new task and add to the tail of the task_link.
 * *ptr: no used. just avoid warning.
 * *return:nothing.
 */
//用来监听客户端的连接,产生任务
void *
task_manager( void *ptr )
{
	int listen_fd;

	if ( -1 == (listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) )
	{
		perror( "socket" );
		goto clean;
	}

	struct ifreq ifr;

	//eno16777736类似于eth0,在Linux系统中可以修改为eth0
	strcpy( ifr.ifr_name, "eno16777736" );
	//获取eno16777736的ip地址
	if ( ioctl( listen_fd, SIOCGIFADDR, &ifr ) < 0 )
	{
		perror( "ioctl" );
		goto clean;
	}

	struct sockaddr_in myaddr;

	myaddr.sin_family	= AF_INET;
	myaddr.sin_port		= htons( PORT );//PORT为9001,在头文件中设置,是全局变量
	myaddr.sin_addr.s_addr	=
		( (struct sockaddr_in *) &(ifr.ifr_addr) )->sin_addr.s_addr;

<span style="white-space:pre">	</span>//输出ip和port信息
<span style="white-space:pre">	</span>printf("server_ip = %s\nserver_port = %d\nlisnum = %d\n", inet_ntoa(myaddr.sin_addr), PORT, LISNUM);

	//绑定IP地址和端口port
	if ( -1 == bind( listen_fd, (struct sockaddr *) &myaddr, sizeof(myaddr) ) )
	{
		perror( "bind" );
		goto clean;
	}
	//监听
	if ( -1 == listen( listen_fd, 5 ) )
	{
		perror( "listen" );
		goto clean;
	}

	/*i is the id of the task */
	int i;
	//开始接受客户端的连接,产生任务
	for ( i = 1; ; i++ )
	{
		int	newfd;
		struct sockaddr_in	client;
		socklen_t len = sizeof(client);

		if ( -1 ==
		     (newfd = accept( listen_fd, (struct sockaddr *) &client, &len ) ) )
		{
			perror( "accept" );
			goto clean;
		}
		/* 打印本次连接的客户端的地址信息 inet_ntoa  ntohs */
		printf( "server: got connection from %s, port %d, socket %d\n", inet_ntoa( client.sin_addr ), ntohs( client.sin_port ), newfd );

		//开始将产生的新任务加入任务队列之中
		TASK_NODE	* temp		= NULL;
		TASK_NODE	* newtask	= (TASK_NODE *) malloc( sizeof(TASK_NODE) );
		if ( newtask == NULL )
		{
			printf( "malloc error" );
			goto clean;
		}

		/*
		 * *initial the attribute of the task.
		 * *because this task havn't add to system,so,no need lock the mutex.
		 */

		newtask->arg = (void *) malloc( 128 );

		memset( newtask->arg, '\0', 128 );
		//任务执行的参数为连接的客户端的socket描述符
		sprintf( newtask->arg, "%d", newfd );
		//新任务的处理函数均为prcoess_client,newfd即为函数prcoess_client的参数
		newtask->fun		= prcoess_client;
		newtask->tid		= 0;
		newtask->work_id	= i;
		newtask->next		= NULL;
		pthread_mutex_init( &newtask->mutex, NULL );

		/*add new task to task_link */
		pthread_mutex_lock( &task_queue_head->mutex );

		/*find the tail of the task link and add the new one to tail 
			开始将产生的新任务加入到任务队列中
		*/
		temp = task_queue_head->head;

		if ( temp == NULL )
		{
			task_queue_head->head = newtask;
		}else  {
			while ( temp->next != NULL )
				temp = temp->next;

			temp->next = newtask;
		}
		task_queue_head->number++;//任务队列数量加一

		pthread_mutex_unlock( &task_queue_head->mutex );

		/*signal the manager thread , task coming 
			告知阻塞等待条件变量task_queue_head->cond的位置,已有未执行的任务
		*/
		pthread_cond_signal( &task_queue_head->cond );
	}

	return;

clean:
	sys_clean();
}


/*
 * *monitor: get the system info
 * *ptr: not used ,only to avoid warning for pthread_create
 * *return: nothing.
 */
//用来输出哪些线程在工作
void *
monitor( void *ptr )
{
	/*in order to prevent warning. */
	ptr = ptr;

	THREAD_NODE * temp_thread = NULL;

	while ( 1 )
	{
		pthread_mutex_lock( &pthread_queue_busy->mutex );

		/*output the busy thread works one by one */
		temp_thread = pthread_queue_busy->head;

		printf( "\n*******************************\n" );
		while ( temp_thread )
		{
			printf( "thread %ld is  execute work_number %d\n",		     \
				temp_thread->tid, temp_thread->work->work_id );
			temp_thread = temp_thread->next;
		}
		printf( "*******************************\n\n" );

		pthread_mutex_unlock( &pthread_queue_busy->mutex );

		sleep( 10 );
	}

	return;
}


/*
 * *sys_clean: clean the system .
 * *this function code need to do to make it more stronger.
 */
//清理函数
void
sys_clean( void )
{
	printf( "the system exit abnormally\n" );
	exit( EXIT_FAILURE );
}

主函数

#include "pthread_pool.h"

//定义三个结构的指针
PTHREAD_QUEUE_T * pthread_queue_idle;           /* the idle thread double link queue. */
PTHREAD_QUEUE_T *pthread_queue_busy;            /* the work thread double link queue. */
TASK_QUEUE_T	*task_queue_head;               /* the task queuee single link list. */

int
main( int argc, char *argv[] )
{
	pthread_t thread_manager_tid, task_manager_tid, monitor_id;

	//初始化空闲线程、在工作线程和要完成的任务
	init_system();

	//创建线程池管理线程、创建任务管理线程和线程状态监视线程
	pthread_create( &thread_manager_tid, NULL, thread_manager, NULL );      /* create thread to manage the thread pool. */
	pthread_create( &task_manager_tid, NULL, task_manager, NULL );          /* create thread recive task from client. */
	pthread_create( &monitor_id, NULL, monitor, NULL );                     /* create thread to monitor the system info. */

	//等待线程退出
	pthread_join( thread_manager_tid, NULL );
	pthread_join( task_manager_tid, NULL );
	pthread_join( monitor_id, NULL );

	//清理服务器,准备退出主函数
	sys_clean();

	return(0);
}

客户端代码

/*************************************************************************
	> File Name: socket_select_client.c
	> Author: genglut
	> Mail: genglut@163.com
	> Created Time: 2014年12月22日 星期一 18时06分06秒
 ************************************************************************/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define MAXBUF 1024

int main(int argc, char *argv[])
{
	int sockfd;
	socklen_t len;
	struct sockaddr_in server_addr;
	char buf[MAXBUF + 1];

	//下面是select用到的变量的定义
	fd_set rfds;
	struct timeval tv;
	int retval;
	int	maxfd = -1;
	
	if(argc != 3)
	{
		printf("error failure, it must be:\n\t\t%s IP port \n", argv[0]);
		exit(EXIT_FAILURE);
	}

	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}

	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(atoi(argv[2]));
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);

	if(connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
	{
		perror("connect");
		exit(EXIT_FAILURE);
	}

	printf("already connected to server %s\n", argv[1]);
	
	
	while(1)
	{
		FD_ZERO(&rfds);//初始化rfds为空
		FD_SET(0, &rfds);//将标准输入的描述符0加入到集合rfds中
		FD_SET(sockfd, &rfds);//将newfd加入到集合rfds中
		maxfd = sockfd + 1;
		tv.tv_sec = 1;//阻塞等待时间为1s
		tv.tv_usec = 0;
		
		retval = select(maxfd, &rfds, NULL, NULL, &tv);//多路复用,同时监测描述符0和newfd
		
		if(retval == -1)//select函数执行出错
		{
			perror("select");
			exit(EXIT_FAILURE);
		}
		else if(retval == 0)//select函数执行超时
			continue;
		else//有描述符引起异常
		{
			if(FD_ISSET(0, &rfds))//判断是不是标准输入0引起的异常
			{
				bzero(buf, sizeof(buf));//清空buf
				fgets(buf, sizeof(buf)-1, stdin);//从终端接收输入

				if(!strncasecmp(buf, "quit", 4))//判断是否为退出
				{
					printf("i will quit!\n");
					break;
				}
				
				len = send(sockfd, buf, strlen(buf)-1, 0);//向客户端发送消息
				if(len > 0)
				{
					printf ("send successful,%d byte send!\n",len);
				}
				else
				{
					printf("message '%s' send failure !\n", buf);
					printf("errno code is %d, errno message is '%s'\n", errno, strerror(errno));
					break;
				}					
			}
			
			if(FD_ISSET(sockfd, &rfds))//判断是不是newfd引起的异常
			{
				bzero(buf, sizeof(buf));
				len = recv(sockfd, buf, sizeof(buf)-1, 0);//从客户端接收消息
				if(len > 0 )
					printf("message recv successful : '%s', %d Byte recv\n", buf, len);
				else if(len < 0)
				{
					printf("recv failure !\nerrno code is %d, errno message is '%s'\n", errno, strerror(errno));
					break;
				}
				else//如果客户端已关闭
				{
					printf("the other one close, quit\n");
					break;
				}					
			}
		}	
	}
	
	close(sockfd);
	printf("i quited!\n");
	return 0;
}

运行结果

服务器:

$ ./pthread_pool

-----------------------------------------
-----------------------------------------

server_ip = 172.18.229.60
server_port = 9001
lisnum = 5

-----------------------------------------
-----------------------------------------

server: got connection from 172.18.229.60, port 56023, socket 4
message recv successful : 'hello', 5 Byte recv

-----------------------------------------
thread 40159 is  execute work_number 1
-----------------------------------------

server: got connection from 172.18.229.60, port 56024, socket 5
message recv successful : 'hi', 2 Byte recv
the other one close quit

-----------------------------------------
thread 40159 is  execute work_number 1
-----------------------------------------

the other one close quit

客户端1:

$ ./client 172.18.229.60 9001
already connected to server 172.18.229.60
hello
send successful,5 byte send!
quit
i will quit!
i quited!

客户端2:

$ ./client 172.18.229.60 9001
already connected to server 172.18.229.60
hi
send successful,2 byte send!
quit
i will quit!
i quited!

原文链接

http://blog.csdn.net/geng823/article/details/42144461

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/gengzj/p/4675765.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值