浅学C++(7)网络编程(网络socket 线程池的封装)

网络socket的封装

network.h

#ifndef NETWORK_H
#define NETWORK_H

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

typedef struct NetWork
{
	int type;		//通信协议类型
	int sock_fd;	//socket描述符
	struct sockaddr_in addr;	//通信地址结构体
	socklen_t addrlen;
	bool is_svr;	//是否是服务端
}NetWork;

typedef struct sockaddr* SP;

// 分配内存、创建socket、准备地址、绑定、监听、连接
NetWork* init_nw(int type,short port,const char* ip,bool is_svr);

//等待连接,只有type是SOCK_STREAM并且是服务端才能使用该函数
NetWork* accept_nw(NetWork* nw);

//具备send\sendto的发送函数
int send_nw(NetWork* nw,const void* buf,size_t len);

//具备recv\recvfrom的接收函数
int recv_nw(NetWork* nw,void* buf,size_t len);

//关闭socket、释放内存
void close_nw(NetWork* nw);

#endif//NETWORK_H

network.c

#include "network.h"

// 分配内存、创建socket、准备地址、绑定、监听、连接
NetWork* init_nw(int type,short port,const char* ip,bool is_svr)
{
	NetWork* nw = malloc(sizeof(NetWork));
	nw->type = type;
	nw->sock_fd = socket(AF_INET,type,0);
	if(0 > nw->sock_fd)
	{
		perror("socket");
		free(nw);
		return NULL;
	}
	nw->addr.sin_family = AF_INET;
	nw->addr.sin_port = htons(port);
	nw->addr.sin_addr.s_addr = inet_addr(ip);
	nw->addrlen = sizeof(struct sockaddr_in);
	nw->is_svr = is_svr;
	if(is_svr)
	{
		if(bind(nw->sock_fd,(SP)&nw->addr,nw->addrlen))
		{
			perror("bind");
			free(nw);
			return NULL;
		}
		if(SOCK_STREAM == type && listen(nw->sock_fd,20))
		{
			perror("listen");
			free(nw);
			return NULL;
		}

	}
	else if(SOCK_STREAM == type)
	{
		if(connect(nw->sock_fd,(SP)&nw->addr,nw->addrlen))
		{
			perror("connect");
			free(nw);
			return NULL;
		}
	}
	return nw;
}

//等待连接,只有type是SOCK_STREAM并且是服务端才能使用该函数
NetWork* accept_nw(NetWork* nw)
{
	if(SOCK_STREAM !=  nw->type || !nw->is_svr)
	{
		printf("只有TCP的服务端对象才能调用此函数\n");	
	}
	//为新的NetWork分配内存
	NetWork* cli_nw = malloc(sizeof(NetWork));
	cli_nw->type = nw->type;
	cli_nw->is_svr = true;
	cli_nw->addrlen = nw->addrlen;

	cli_nw->sock_fd = accept(nw->sock_fd,(SP)&cli_nw->addr,&cli_nw->addrlen);
	if(0 >= cli_nw->sock_fd)
	{
		perror("accept");
		free(cli_nw);
		return NULL;
	}
	return cli_nw;

}

//具备send\sendto的发送函数
int send_nw(NetWork* nw,const void* buf,size_t len)
{
	if(SOCK_STREAM == nw->type)
		return send(nw->sock_fd,buf,len,0);
	else
		return sendto(nw->sock_fd,buf,len,0,(SP)&nw->addr,nw->addrlen);
}

//具备recv\recvfrom的接收函数
int recv_nw(NetWork* nw,void* buf,size_t len)
{
	if(SOCK_STREAM == nw->type)
		return recv(nw->sock_fd,buf,len,0);
	else
		return recvfrom(nw->sock_fd,buf,len,0,(SP)&nw->addr,&nw->addrlen);
}

//关闭socket、释放内存
void close_nw(NetWork* nw)
{
	close(nw->sock_fd);
	free(nw);
}

线程池的封装

由于线程池需要用到队列 我们先对 队列 进行封装

queue.h

#ifndef QUEUE_H
#define QUEUE_H

#include <stdbool.h>
#include <stdio.h>

typedef struct Queue
{
	void** arr;//内存首地址
	size_t cal;//容量
	int front;//队头
	int back;//队尾
}Queue;

//创建队列
Queue* create_queue(size_t cal);
//销毁队列
void destory_queue(Queue* queue);
//队空
bool empty_queue(Queue* queue);
//队满
bool full_queue(Queue* queue);
//入队
void push_queue(Queue* queue,void* arg);
//出队
void pop_queue(Queue* queue);
//队头
void* front_queue(Queue* queue);
//队尾
void* back_queue(Queue* queue);

#endif//QUEUE_H

queue.c

#include <stdlib.h>
#include "queue.h"


//创建队列
Queue* create_queue(size_t cal)
{
	Queue* queue = malloc(sizeof(Queue));
	queue->arr = malloc(sizeof(void*)*(cal+1));
	queue->cal = cal+1;
	queue->front = 0;
	queue->back = 0;
	return queue;
}
//销毁队列
void destory_queue(Queue* queue)
{
	free(queue->arr);
	free(queue);
}
//队空
bool empty_queue(Queue* queue)
{
	return queue->front == queue->back;
}
//队满
bool full_queue(Queue* queue)
{
	return (queue->back+1)%queue->cal == queue->front;
}
//入队
void push_queue(Queue* queue,void* arg)
{
	queue->arr[queue->back++] = arg;
	queue->back %= queue->cal;
}
//出队
void pop_queue(Queue* queue)
{
	queue->front = (queue->front+1)%queue->cal;
}
//队头
void* front_queue(Queue* queue)
{
	return queue->arr[queue->front];
}
//队尾
void* back_queue(Queue* queue)
{
	return queue->arr[(queue->back-1+queue->cal)%queue->cal];
}

threadpool.h

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include "queue.h"
#include <pthread.h>

typedef void (*WorkFP)(void*);//线程真正的业务逻辑函数格式

typedef struct Threadpool
{
	int thread_cnt;//线程数量
	pthread_t* tids;//线程ID的数组首地址
	Queue* store_buf;//队列仓库
	pthread_mutex_t flock;//队头互斥量
	pthread_mutex_t block;//队尾互斥量
	pthread_cond_t full;//满仓的条件变量
	pthread_cond_t empty;//空仓的条件变量
	WorkFP workfp;//线程的业务逻辑函数
}Threadpool;

//创建线程池
Threadpool* create_threadpool(int thread_cnt,int store_cal,WorkFP workfp);
//启动线程池
void start_threadpool(Threadpool* threadpool);
//生产数据
void push_threadpool(Threadpool* threadpool,void* data);
//消费数据
void* pop_threadpool(Threadpool* threadpool);
//销毁线程池
void destory_theadpool(Threadpool* threadpool);

#endif//THREADPOOL_H

threadpool.c

#include <stdlib.h>
#include "threadpool.h"

static void* run(void* arg)
{
	Threadpool* threadpool = (Threadpool*)arg;
	for(;;)
	{
		//消费数据
		void* data = pop_threadpool(threadpool);
		//如果能拿到数据,则执行业务逻辑函数
		threadpool->workfp(data);
		//本次任务结束,继续重新消费数据
	}
}

//创建线程池
Threadpool* create_threadpool(int thread_cnt,int store_cal,WorkFP workfp)
{
	//申请线程池内存
	Threadpool* threadpool = malloc(sizeof(Threadpool));
	threadpool->tids = malloc(sizeof(pthread_t)*thread_cnt);
	threadpool->thread_cnt = thread_cnt;
	threadpool->store_buf = create_queue(store_cal);
	threadpool->workfp = workfp;

	pthread_mutex_init(&threadpool->flock,NULL);
	pthread_mutex_init(&threadpool->block,NULL);
	pthread_cond_init(&threadpool->full,NULL);
	pthread_cond_init(&threadpool->empty,NULL);
	return threadpool;
}
//启动线程池
void start_threadpool(Threadpool* threadpool)
{
	for(int i=0;i<threadpool->thread_cnt;i++)
	{
		pthread_create(threadpool->tids+i,NULL,run,threadpool);	
	}
}
//生产数据
void push_threadpool(Threadpool* threadpool,void* data)
{
	//尝试对队尾加锁
	pthread_mutex_lock(&threadpool->block);
	while(full_queue(threadpool->store_buf))
	{
		//唤醒消费者线程
		pthread_cond_signal(&threadpool->empty);
		//休眠并解锁队尾
		pthread_cond_wait(&threadpool->full,&threadpool->block);
	}
	//生产数据并存入队尾
	push_queue(threadpool->store_buf,data);
	//唤醒消费者线程
	pthread_cond_signal(&threadpool->empty);
	//解锁队尾
	pthread_mutex_unlock(&threadpool->block);

}
//消费数据
void* pop_threadpool(Threadpool* threadpool)
{
	pthread_mutex_lock(&threadpool->flock);
	while(empty_queue(threadpool->store_buf))
	{
		pthread_cond_signal(&threadpool->full);
		pthread_cond_wait(&threadpool->empty,&threadpool->flock);
	}
	void* data = front_queue(threadpool->store_buf);
	pop_queue(threadpool->store_buf);
	pthread_cond_signal(&threadpool->full);
	pthread_mutex_unlock(&threadpool->flock);
	return data;
}
//销毁线程池
void destory_theadpool(Threadpool* threadpool)
{
	for(int i=0;i<threadpool->thread_cnt;i++)
	{
		pthread_cancel(threadpool->tids[i]);	
	}
	pthread_mutex_destroy(&threadpool->flock);
	pthread_mutex_destroy(&threadpool->block);
	pthread_cond_destroy(&threadpool->full);
	pthread_cond_destroy(&threadpool->empty);
	destory_queue(threadpool->store_buf);
	free(threadpool->tids);
	free(threadpool);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值