TCP高性能服务器编程----进程池、线程池

本文深入探讨了线程池技术的工作原理,通过对比多线程,突显了线程池在资源管理和性能优化上的优势。文章详细介绍了线程池的创建、线程阻塞、客户端服务分配以及客户端文件描述符的传递机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概念
服务器启动则创建n(固定值,有限值)个子进程或者函数线程,创建的子进程或者函数线程在服务器终止时销毁,如果有客户端链接,则分配一个子进程或者线程为其服务,服务完成之后则继续等待分配下一个客户端

二、线程池相比多线程的优势
1、创建的进程或者线程是有限的,服务器的系统代价比较小,一般不会达到系统限制的值
2、服务器不需要频繁的创建、销毁进程或者线程,只是在服务器启动时创建,结束时销毁
3、创建的进程或者线程不是为一个客户端服务,可以串行为多个客户端服务,
4、客户端连接上以后,不需要再去创建进程或者线程,只需要分配进程池或线程池中的进程或者线程,对于客户端的速度就能快一些

线程池代码:
主线程与所有的函数线程同步执行,在这里用信号量,而不是互斥锁,因为临界资源不止有一个

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <semaphore.h>

#define THREADNUM  3
#define CLIENTNUM  10
sem_t sem;
pthread_mutex_t  mutex;

int ClientFds[CLIENTNUM];

void Init_ClientFds()
{
	int i = 0;
	for(; i < CLIENTNUM; ++i)
	{
		ClientFds[i] = -1;
	}
}

void Insert_Client(int fd)
{
	pthread_mutex_lock(&mutex);

	int i = 0;
	for(; i < CLIENTNUM; ++i)
	{
		if(ClientFds[i] == -1)
		{
			ClientFds[i] = fd;
			break;
		}
	}

	pthread_mutex_unlock(&mutex);
}

int Get_Client()
{
	pthread_mutex_lock(&mutex);

	int i = 0, c = -1;
	for(; i < CLIENTNUM; ++i)
	{
		if(ClientFds[i] != -1)
		{
			c = ClientFds[i];
			ClientFds[i] = -1;
			break;
		}
	}

	pthread_mutex_unlock(&mutex);

	return c;
}

void * DealClient(void * arg)
{
	while(1)
	{
		sem_wait(&sem);
		int  c = Get_Client();
		while(1)
		{
			char data[128] = {0};
			int n = recv(c, data, 127, 0);
			if(n <= 0)
			{
				close(c);
				break;
			}

			printf("%s\n", data);

			send(c, "OK", 2, 0);
		}
	}
}

int main()
{
	int listenfd = socket(AF_INET, SOCK_STREAM, 0);
	assert(listenfd != -1);

	struct sockaddr_in ser;
	memset(&ser, 0, sizeof(ser));
	ser.sin_family = AF_INET;
	ser.sin_port = htons(6000);
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");

	int res = bind(listenfd, (struct sockaddr*)&ser, sizeof(ser));
	assert(res != -1);

	listen(listenfd, 5);

	sem_init(&sem, 0, 0);
	pthread_mutex_init(&mutex, NULL);
	Init_ClientFds();

	//  创建线程池
	int i = 0;
	for(; i < THREADNUM; ++i)
	{
		pthread_t id;
		int res = pthread_create(&id, NULL, DealClient, NULL);
		assert(res  == 0);
	}

	while(1)
	{
		struct sockaddr_in cli;
		int len = sizeof(cli);

		int c = accept(listenfd, (struct sockaddr*)&cli, &len);
		assert(c != -1);

		Insert_Client(c);  //  将c传递给函数线程
		sem_post(&sem);   //  V操作
	}
}

需要注意的有
1、线程如何阻塞在线程池中
P操作
2、如何分配一个线程为客户端服务
主线程接收一个客户端连接后执行V操作
3、主线程如何传递客户端连接的文件描述符
全局维护一个数组或者链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值