基础组件(线程池、内存池、异步请求池、Mysql连接池)

news2024/11/27 8:34:22

文章目录

  • 1、概述
  • 2、线程池
  • 2、异步请求池
  • 3、内存池

1、概述

池化技术,减少了资源创建次数,提高了程序响应性能,特别是在高并发场景下,当程序7*24小时运行,创建资源可能会出现耗时较长和失败等问题,池化技术,主要是程序初始化之前创建多个可用连接,集中管理起来,后续直接使用,使用完并归还。

2、线程池

线程池主要解决问题:
1、解决线程创建和消耗所浪费的资源和时间
2、控制线程数量,减少资源竞争

代码解读

一共由三个接口组成:
1、CreatePthreadPool创建工作线程
初始化线程池结构下的条件变量和互斥锁,创建多个线程通过头插法,插入到线程池结构worker成员中
2、thread_func线程入口函数
进入while循环,第一件事先拿锁,然后再去判断,任务队列中是否有数据,要是没有则进入循环中的条件等待,进入条件等待会先释放锁,所以初始化完成之后所有线程全部都会进入条件等待,然后一旦条件满足则会去拿锁。
3、threadPoolQueue将任务加入到任务链表中
先加锁,然后通过头插法插入到线程池结构中的wait_jobs成员中,通知条件变量,然后解锁
4、threadPoolShutdown回收线程池中线程
将工作线程中的标识位全部置为一,然后通知所有线程,然后等待回收所有线程并释放每个节点

总结

线程池就是一个很典型的生产者消费者模型,不断地向任务队列中投放任务,工作线程不断地去队伍队列中去取任务消费掉。

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

#define LL_ADD(item, list) do { 	\
	item->prev = NULL;				\
	item->next = list;				\
	list = item;					\
} while(0)

#define LL_REMOVE(item, list) do {						\
	if (item->prev != NULL) item->prev->next = item->next;	\
	if (item->next != NULL) item->next->prev = item->prev;	\
	if (list == item) list = item->next;					\
	item->prev = item->next = NULL;							\
} while(0)

// 工作线程结构体
typedef struct NWORKER{
    pthread_t id;               // 线程id
    int terminate;              // 终止条件
    struct NTHREADPOLL *worqueue;
    struct NWORKER *prev;       // 前向指针
    struct NWORKER *next;       // 后项指针
}nWorker;

// 任务队列
typedef struct NJOB{
    void (*job_function)(struct NJOB* job);
    void* user_data;
    struct NJOB *prev;
    struct NJOB *next;
}nJob;

typedef struct NTHREADPOLL{
    struct NWORKER *workers;
    struct NJOB *wait_jobs;

    pthread_cond_t cond;
    pthread_mutex_t mtx;
}nThreadpoll;

// 操作线程池函数
#define MAX_PTHREAD 80
#define MAX_JOB 8

// 毁掉函数
void job_fun(nJob *job){
    if(job == NULL) return;
    int *data = (int*)job->user_data;
    printf("user_data:%d-thread_id:%ld,line:%d\n",*data,pthread_self(),__LINE__);

    free(job->user_data);
    job->user_data = NULL;
    free(job);
    job = NULL;
    return;
}

// 线程入口函数
void* thread_func(void* data){
    nWorker *worker = (nWorker*)data;
    while (1)
    {
        pthread_mutex_lock(&(worker->worqueue->mtx));
        while(worker->worqueue->wait_jobs == NULL){
            if(worker->terminate) break;
            pthread_cond_wait(&(worker->worqueue->cond),&(worker->worqueue->mtx));
        }
        if(worker->terminate){
            pthread_mutex_unlock(&(worker->worqueue->mtx));
            break;
        }
        nJob *job = worker->worqueue->wait_jobs;
        if(job != NULL)
            LL_REMOVE(job,worker->worqueue->wait_jobs);
        pthread_mutex_unlock(&(worker->worqueue->mtx));
        if(job == NULL) continue;
        job->job_function(job);
    }
    // free(worker);
    // worker = NULL;
    pthread_exit(0);
}

// 创造线程
int CreatePthreadPool(nThreadpoll* threadpoll,int max_pthread)
{
    if(max_pthread <= 0) max_pthread = MAX_PTHREAD;
    memset(threadpoll,0x00,sizeof(nThreadpoll));
    
	pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
	memcpy(&threadpoll->cond, &blank_cond, sizeof(threadpoll->cond));
	
	pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;
	memcpy(&threadpoll->mtx, &blank_mutex, sizeof(threadpoll->mtx));
    int i;
    for(i=0; i<max_pthread; i++){
         
        nWorker *worker = (nWorker*)malloc(sizeof(nWorker));
        if(worker == NULL){
            perror("threadpoll->workers");
            return -1;
        }
        memset(worker,0x00,sizeof(nWorker));
        worker->worqueue = threadpoll;
        worker->terminate = 0;
        int ret = pthread_create(&(worker->id),NULL,thread_func,(void*)worker);
        if(ret != 0){
            perror("pthread_create");
            free(worker);
            worker = NULL;
            return -1;
        }
        LL_ADD(worker,worker->worqueue->workers);
    }
    return 0;
}

// 向线程中添加任务,唤醒一个线程去处理
void threadPoolQueue(nThreadpoll* threadpool,nJob *job){
    pthread_mutex_lock(&(threadpool->mtx));
    
    LL_ADD(job,threadpool->wait_jobs);
    
    pthread_cond_signal(&(threadpool->cond));
    pthread_mutex_unlock(&(threadpool->mtx));
    return;
}

void threadPoolShutdown(nThreadpoll *workerqueue){
    nWorker *woker = NULL;
    for(woker = workerqueue->workers;woker!=NULL;woker = woker->next){
        woker->terminate = 1;
    }
	pthread_cond_broadcast(&workerqueue->cond);
    struct NWORKER *tmp = workerqueue->workers;
    while (tmp)
    {
        pthread_join(tmp->id,NULL);
        if(tmp){
            free(tmp);
            tmp = NULL;
        }
        tmp = tmp->next;
    }
    pthread_cond_destroy(&workerqueue->cond);
    pthread_mutex_destroy(&workerqueue->mtx);
    workerqueue->workers = NULL;
	workerqueue->wait_jobs = NULL;
}

int main(){
    nThreadpoll workerQueue;
    if(CreatePthreadPool(&workerQueue,MAX_PTHREAD) != 0){
        perror("CreatePthreadPool faile");
        return -1;
    }
    int i;
    for(i=0;i<MAX_JOB;i++){
        nJob *job = (nJob*)malloc(sizeof(nJob));
        if(job == NULL){
            perror("nJob malloc faile");
            exit(-1);
        }
        job->job_function = job_fun;
        job->user_data = (int*)malloc(sizeof(int));
        *(int*)job->user_data = i;
        threadPoolQueue(&workerQueue,job);
    }
    getchar();
    return 0;
}

2、异步请求池

当我们向数据库或者DNS服务器发送请求时,需要同步等待他的返回结果,这个过程是比较耗时的,所以衍生出异步发起请求,当发出请求之后,不等待请求的响应,而是通过一个线程去监听,主线程去做其他事情,当请求响应之后如何去做其他事情。
在这里插入图片描述
在这里插入图片描述

同步向DNS服务器发送请求




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

#include <errno.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <sys/epoll.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <pthread.h>


#define DNS_SVR				"114.114.114.114"


#define DNS_HOST			0x01
#define DNS_CNAME			0x05



struct dns_header {
	unsigned short id;
	unsigned short flags;
	unsigned short qdcount;
	unsigned short ancount;
	unsigned short nscount;
	unsigned short arcount;
};

struct dns_question {
	int length;
	unsigned short qtype;
	unsigned short qclass;
	char *qname;
};

struct dns_item {
	char *domain;
	char *ip;
};

int dns_create_header(struct dns_header *header) {

	if (header == NULL) return -1;
	memset(header, 0, sizeof(struct dns_header));

	srandom(time(NULL));

	header->id = random();
	header->flags |= htons(0x0100);
	header->qdcount = htons(1);

	return 0;
}

int dns_create_question(struct dns_question *question, const char *hostname) {

	if (question == NULL) return -1;
	memset(question, 0, sizeof(struct dns_question));

	question->qname = (char*)malloc(strlen(hostname) + 2);
	if (question->qname == NULL) return -2;

	question->length = strlen(hostname) + 2;

	question->qtype = htons(1);
	question->qclass = htons(1);

	const char delim[2] = ".";

	char *hostname_dup = strdup(hostname);
	char *token = strtok(hostname_dup, delim);

	char *qname_p = question->qname;

	while (token != NULL) {

		size_t len = strlen(token);

		*qname_p = len;
		qname_p ++;

		strncpy(qname_p, token, len+1);
		qname_p += len;

		token = strtok(NULL, delim);
	}

	free(hostname_dup);

	return 0;
	
}

int dns_build_request(struct dns_header *header, struct dns_question *question, char *request) {

	int header_s = sizeof(struct dns_header);
	int question_s = question->length + sizeof(question->qtype) + sizeof(question->qclass);

	int length = question_s + header_s;

	int offset = 0;
	memcpy(request+offset, header, sizeof(struct dns_header));
	offset += sizeof(struct dns_header);

	memcpy(request+offset, question->qname, question->length);
	offset += question->length;

	memcpy(request+offset, &question->qtype, sizeof(question->qtype));
	offset += sizeof(question->qtype);

	memcpy(request+offset, &question->qclass, sizeof(question->qclass));

	return length;
	
}

static int is_pointer(int in) {
	return ((in & 0xC0) == 0xC0);
}


static void dns_parse_name(unsigned char *chunk, unsigned char *ptr, char *out, int *len) {

	int flag = 0, n = 0, alen = 0;
	char *pos = out + (*len);

	while (1) {

		flag = (int)ptr[0];
		if (flag == 0) break;

		if (is_pointer(flag)) {
			
			n = (int)ptr[1];
			ptr = chunk + n;
			dns_parse_name(chunk, ptr, out, len);
			break;
			
		} else {

			ptr ++;
			memcpy(pos, ptr, flag);
			pos += flag;
			ptr += flag;

			*len += flag;
			if ((int)ptr[0] != 0) {
				memcpy(pos, ".", 1);
				pos += 1;
				(*len) += 1;
			}
		}
	
	}
	
}


static int dns_parse_response(char *buffer, struct dns_item **domains) {

	int i = 0;
	unsigned char *ptr = buffer;

	ptr += 4;
	int querys = ntohs(*(unsigned short*)ptr);

	ptr += 2;
	int answers = ntohs(*(unsigned short*)ptr);

	ptr += 6;
	for (i = 0;i < querys;i ++) {
		while (1) {
			int flag = (int)ptr[0];
			ptr += (flag + 1);

			if (flag == 0) break;
		}
		ptr += 4;
	}

	char cname[128], aname[128], ip[20], netip[4];
	int len, type, ttl, datalen;

	int cnt = 0;
	struct dns_item *list = (struct dns_item*)calloc(answers, sizeof(struct dns_item));
	if (list == NULL) {
		return -1;
	}

	for (i = 0;i < answers;i ++) {
		
		bzero(aname, sizeof(aname));
		len = 0;

		dns_parse_name(buffer, ptr, aname, &len);
		ptr += 2;

		type = htons(*(unsigned short*)ptr);
		ptr += 4;

		ttl = htons(*(unsigned short*)ptr);
		ptr += 4;

		datalen = ntohs(*(unsigned short*)ptr);
		ptr += 2;

		if (type == DNS_CNAME) {

			bzero(cname, sizeof(cname));
			len = 0;
			dns_parse_name(buffer, ptr, cname, &len);
			ptr += datalen;
			
		} else if (type == DNS_HOST) {

			bzero(ip, sizeof(ip));

			if (datalen == 4) {
				memcpy(netip, ptr, datalen);
				inet_ntop(AF_INET , netip , ip , sizeof(struct sockaddr));

				printf("%s has address %s\n" , aname, ip);
				printf("\tTime to live: %d minutes , %d seconds\n", ttl / 60, ttl % 60);

				list[cnt].domain = (char *)calloc(strlen(aname) + 1, 1);
				memcpy(list[cnt].domain, aname, strlen(aname));
				
				list[cnt].ip = (char *)calloc(strlen(ip) + 1, 1);
				memcpy(list[cnt].ip, ip, strlen(ip));
				
				cnt ++;
			}
			
			ptr += datalen;
		}
	}

	*domains = list;
	ptr += 2;

	return cnt;
	
}


int dns_client_commit(const char *domain) {

	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		perror("create socket failed\n");
		exit(-1);
	}

	printf("url:%s\n", domain);

	struct sockaddr_in dest;
	bzero(&dest, sizeof(dest));
	dest.sin_family = AF_INET;
	dest.sin_port = htons(53);
	dest.sin_addr.s_addr = inet_addr(DNS_SVR);
	
	int ret = connect(sockfd, (struct sockaddr*)&dest, sizeof(dest));
	printf("connect :%d\n", ret);

	struct dns_header header = {0};
	dns_create_header(&header);

	struct dns_question question = {0};
	dns_create_question(&question, domain);

	char request[1024] = {0};
	int req_len = dns_build_request(&header, &question, request);
	int slen = sendto(sockfd, request, req_len, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr));

	char buffer[1024] = {0};
	struct sockaddr_in addr;
	size_t addr_len = sizeof(struct sockaddr_in);
		
	int n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);
		
	printf("recvfrom n : %d\n", n);
	struct dns_item *domains = NULL;
	dns_parse_response(buffer, &domains);

	return 0;
}

char *domain[] = {
//	"www.ntytcp.com",
	"bojing.wang",
	"www.baidu.com",
	"tieba.baidu.com",
	"news.baidu.com",
	"zhidao.baidu.com",
	"music.baidu.com",
	"image.baidu.com",
	"v.baidu.com",
	"map.baidu.com",
	"baijiahao.baidu.com",
	"xueshu.baidu.com",
	"cloud.baidu.com",
	"www.163.com",
	"open.163.com",
	"auto.163.com",
	"gov.163.com",
	"money.163.com",
	"sports.163.com",
	"tech.163.com",
	"edu.163.com",
	"www.taobao.com",
	"q.taobao.com",
	"sf.taobao.com",
	"yun.taobao.com",
	"baoxian.taobao.com",
	"www.tmall.com",
	"suning.tmall.com",
	"www.tencent.com",
	"www.qq.com",
	"www.aliyun.com",
	"www.ctrip.com",
	"hotels.ctrip.com",
	"hotels.ctrip.com",
	"vacations.ctrip.com",
	"flights.ctrip.com",
	"trains.ctrip.com",
	"bus.ctrip.com",
	"car.ctrip.com",
	"piao.ctrip.com",
	"tuan.ctrip.com",
	"you.ctrip.com",
	"g.ctrip.com",
	"lipin.ctrip.com",
	"ct.ctrip.com"
};



int main(int argc, char *argv[]) {

	int count = sizeof(domain) / sizeof(domain[0]);
	int i = 0;

	for (i = 0;i < count;i ++) {
		dns_client_commit(domain[i]);
	}

	getchar();
	
}

异步发送请求

1、dns_async_client_init初始化函数
创建epoll、创建线程,用来监控dns的响应消息
2、dns_async_client_commit创建连接,发送请求,将fd加入到epoll中进行监听
3、dns_async_client_proc线程入口函数
通过epoll_wait进行监听,调用取出数据,调用对应的回调函数,epoll_ctl删除节点。




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

#include <errno.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <sys/epoll.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <pthread.h>


#define DNS_SVR				"114.114.114.114"


#define DNS_HOST			0x01
#define DNS_CNAME			0x05

#define ASYNC_CLIENT_NUM		1024


struct dns_header {
	unsigned short id;
	unsigned short flags;
	unsigned short qdcount;
	unsigned short ancount;
	unsigned short nscount;
	unsigned short arcount;
};

struct dns_question {
	int length;
	unsigned short qtype;
	unsigned short qclass;
	char *qname;
};

struct dns_item {
	char *domain;
	char *ip;
};

typedef void (*async_result_cb)(struct dns_item *list, int count);


struct async_context {
	int epfd;
};

struct ep_arg {
	int sockfd;
	async_result_cb cb;
};

int dns_create_header(struct dns_header *header) {

	if (header == NULL) return -1;
	memset(header, 0, sizeof(struct dns_header));

	srandom(time(NULL));

	header->id = random();
	header->flags |= htons(0x0100);
	header->qdcount = htons(1);

	return 0;
}

int dns_create_question(struct dns_question *question, const char *hostname) {

	if (question == NULL) return -1;
	memset(question, 0, sizeof(struct dns_question));

	question->qname = (char*)malloc(strlen(hostname) + 2);
	if (question->qname == NULL) return -2;

	question->length = strlen(hostname) + 2;

	question->qtype = htons(1);
	question->qclass = htons(1);

	const char delim[2] = ".";

	char *hostname_dup = strdup(hostname);
	char *token = strtok(hostname_dup, delim);

	char *qname_p = question->qname;

	while (token != NULL) {

		size_t len = strlen(token);

		*qname_p = len;
		qname_p ++;

		strncpy(qname_p, token, len+1);
		qname_p += len;

		token = strtok(NULL, delim);
	}

	free(hostname_dup);

	return 0;
	
}

int dns_build_request(struct dns_header *header, struct dns_question *question, char *request) {

	int header_s = sizeof(struct dns_header);
	int question_s = question->length + sizeof(question->qtype) + sizeof(question->qclass);

	int length = question_s + header_s;

	int offset = 0;
	memcpy(request+offset, header, sizeof(struct dns_header));
	offset += sizeof(struct dns_header);

	memcpy(request+offset, question->qname, question->length);
	offset += question->length;

	memcpy(request+offset, &question->qtype, sizeof(question->qtype));
	offset += sizeof(question->qtype);

	memcpy(request+offset, &question->qclass, sizeof(question->qclass));

	return length;
	
}

static int is_pointer(int in) {
	return ((in & 0xC0) == 0xC0);
}

static int set_block(int fd, int block) {
	int flags = fcntl(fd, F_GETFL, 0);
	if (flags < 0) return flags;

	if (block) {        
		flags &= ~O_NONBLOCK;    
	} else {        
		flags |= O_NONBLOCK;    
	}

	if (fcntl(fd, F_SETFL, flags) < 0) return -1;

	return 0;
}

static void dns_parse_name(unsigned char *chunk, unsigned char *ptr, char *out, int *len) {

	int flag = 0, n = 0, alen = 0;
	char *pos = out + (*len);

	while (1) {

		flag = (int)ptr[0];
		if (flag == 0) break;

		if (is_pointer(flag)) {
			
			n = (int)ptr[1];
			ptr = chunk + n;
			dns_parse_name(chunk, ptr, out, len);
			break;
			
		} else {

			ptr ++;
			memcpy(pos, ptr, flag);
			pos += flag;
			ptr += flag;

			*len += flag;
			if ((int)ptr[0] != 0) {
				memcpy(pos, ".", 1);
				pos += 1;
				(*len) += 1;
			}
		}
	
	}
	
}


static int dns_parse_response(char *buffer, struct dns_item **domains) {

	int i = 0;
	unsigned char *ptr = buffer;

	ptr += 4;
	int querys = ntohs(*(unsigned short*)ptr);

	ptr += 2;
	int answers = ntohs(*(unsigned short*)ptr);

	ptr += 6;
	for (i = 0;i < querys;i ++) {
		while (1) {
			int flag = (int)ptr[0];
			ptr += (flag + 1);

			if (flag == 0) break;
		}
		ptr += 4;
	}

	char cname[128], aname[128], ip[20], netip[4];
	int len, type, ttl, datalen;

	int cnt = 0;
	struct dns_item *list = (struct dns_item*)calloc(answers, sizeof(struct dns_item));
	if (list == NULL) {
		return -1;
	}

	for (i = 0;i < answers;i ++) {
		
		bzero(aname, sizeof(aname));
		len = 0;

		dns_parse_name(buffer, ptr, aname, &len);
		ptr += 2;

		type = htons(*(unsigned short*)ptr);
		ptr += 4;

		ttl = htons(*(unsigned short*)ptr);
		ptr += 4;

		datalen = ntohs(*(unsigned short*)ptr);
		ptr += 2;

		if (type == DNS_CNAME) {

			bzero(cname, sizeof(cname));
			len = 0;
			dns_parse_name(buffer, ptr, cname, &len);
			ptr += datalen;
			
		} else if (type == DNS_HOST) {

			bzero(ip, sizeof(ip));

			if (datalen == 4) {
				memcpy(netip, ptr, datalen);
				inet_ntop(AF_INET , netip , ip , sizeof(struct sockaddr));

				printf("%s has address %s\n" , aname, ip);
				printf("\tTime to live: %d minutes , %d seconds\n", ttl / 60, ttl % 60);

				list[cnt].domain = (char *)calloc(strlen(aname) + 1, 1);
				memcpy(list[cnt].domain, aname, strlen(aname));
				
				list[cnt].ip = (char *)calloc(strlen(ip) + 1, 1);
				memcpy(list[cnt].ip, ip, strlen(ip));
				
				cnt ++;
			}
			
			ptr += datalen;
		}
	}

	*domains = list;
	ptr += 2;

	return cnt;
	
}


int dns_client_commit(const char *domain) {

	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		perror("create socket failed\n");
		exit(-1);
	}

	printf("url:%s\n", domain);

	set_block(sockfd, 0); //nonblock

	struct sockaddr_in dest;
	bzero(&dest, sizeof(dest));
	dest.sin_family = AF_INET;
	dest.sin_port = htons(53);
	dest.sin_addr.s_addr = inet_addr(DNS_SVR);
	
	int ret = connect(sockfd, (struct sockaddr*)&dest, sizeof(dest));
	//printf("connect :%d\n", ret);

	struct dns_header header = {0};
	dns_create_header(&header);

	struct dns_question question = {0};
	dns_create_question(&question, domain);

	char request[1024] = {0};
	int req_len = dns_build_request(&header, &question, request);
	int slen = sendto(sockfd, request, req_len, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr));

	while (1) {
		char buffer[1024] = {0};
		struct sockaddr_in addr;
		size_t addr_len = sizeof(struct sockaddr_in);
	
		int n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);
		if (n <= 0) continue;
		
		printf("recvfrom n : %d\n", n);
		struct dns_item *domains = NULL;
		dns_parse_response(buffer, &domains);

		break;
	}

	return 0;
}

void dns_async_client_free_domains(struct dns_item *list, int count) {
	int i = 0;

	for (i = 0;i < count;i ++) {
		free(list[i].domain);
		free(list[i].ip);
	}

	free(list);
}


//dns_async_client_proc()
//epoll_wait
//result callback
static void* dns_async_client_proc(void *arg) {
	struct async_context *ctx = (struct async_context*)arg;

	int epfd = ctx->epfd;

	while (1) {

		struct epoll_event events[ASYNC_CLIENT_NUM] = {0};

		int nready = epoll_wait(epfd, events, ASYNC_CLIENT_NUM, -1);
		if (nready < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			} else {
				break;
			}
		} else if (nready == 0) {
			continue;
		}

		printf("nready:%d\n", nready);
		int i = 0;
		for (i = 0;i < nready;i ++) {

			struct ep_arg *data = (struct ep_arg*)events[i].data.ptr;
			int sockfd = data->sockfd;

			char buffer[1024] = {0};
			struct sockaddr_in addr;
			size_t addr_len = sizeof(struct sockaddr_in);
			int n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);

			struct dns_item *domain_list = NULL;
			int count = dns_parse_response(buffer, &domain_list);

			data->cb(domain_list, count); //call cb
			
			int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
			//printf("epoll_ctl DEL --> sockfd:%d\n", sockfd);

			close(sockfd); /

			dns_async_client_free_domains(domain_list, count);
			free(data);

		}
		
	}
	
}



//dns_async_client_init()
//epoll init
//thread init
struct async_context *dns_async_client_init(void) {

	int epfd = epoll_create(1); // 
	if (epfd < 0) return NULL;

	struct async_context *ctx = calloc(1, sizeof(struct async_context));
	if (ctx == NULL) {
		close(epfd);
		return NULL;
	}
	ctx->epfd = epfd;

	pthread_t thread_id;
	int ret = pthread_create(&thread_id, NULL, dns_async_client_proc, ctx);
	if (ret) {
		perror("pthread_create");
		return NULL;
	}
	usleep(1); //child go first

	return ctx;
}


//dns_async_client_commit(ctx, domain)
//socket init
//dns_request
//sendto dns send
int dns_async_client_commit(struct async_context* ctx, const char *domain, async_result_cb cb) {

	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		perror("create socket failed\n");
		exit(-1);
	}

	printf("url:%s\n", domain);

	set_block(sockfd, 0); //nonblock

	struct sockaddr_in dest;
	bzero(&dest, sizeof(dest));
	dest.sin_family = AF_INET;
	dest.sin_port = htons(53);
	dest.sin_addr.s_addr = inet_addr(DNS_SVR);
	
	int ret = connect(sockfd, (struct sockaddr*)&dest, sizeof(dest));
	//printf("connect :%d\n", ret);

	struct dns_header header = {0};
	dns_create_header(&header);

	struct dns_question question = {0};
	dns_create_question(&question, domain);

	char request[1024] = {0};
	int req_len = dns_build_request(&header, &question, request);
	int slen = sendto(sockfd, request, req_len, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr));

	struct ep_arg *eparg = (struct ep_arg*)calloc(1, sizeof(struct ep_arg));
	if (eparg == NULL) return -1;
	eparg->sockfd = sockfd;
	eparg->cb = cb;

	struct epoll_event ev;
	ev.data.ptr = eparg;
	ev.events = EPOLLIN;

	ret = epoll_ctl(ctx->epfd, EPOLL_CTL_ADD, sockfd, &ev); 
	//printf(" epoll_ctl ADD: sockfd->%d, ret:%d\n", sockfd, ret);

	return ret;


	
}


char *domain[] = {
	"www.ntytcp.com",
	"bojing.wang",
	"www.baidu.com",
	"tieba.baidu.com",
	"news.baidu.com",
	"zhidao.baidu.com",
	"music.baidu.com",
	"image.baidu.com",
	"v.baidu.com",
	"map.baidu.com",
	"baijiahao.baidu.com",
	"xueshu.baidu.com",
	"cloud.baidu.com",
	"www.163.com",
	"open.163.com",
	"auto.163.com",
	"gov.163.com",
	"money.163.com",
	"sports.163.com",
	"tech.163.com",
	"edu.163.com",
	"www.taobao.com",
	"q.taobao.com",
	"sf.taobao.com",
	"yun.taobao.com",
	"baoxian.taobao.com",
	"www.tmall.com",
	"suning.tmall.com",
	"www.tencent.com",
	"www.qq.com",
	"www.aliyun.com",
	"www.ctrip.com",
	"hotels.ctrip.com",
	"hotels.ctrip.com",
	"vacations.ctrip.com",
	"flights.ctrip.com",
	"trains.ctrip.com",
	"bus.ctrip.com",
	"car.ctrip.com",
	"piao.ctrip.com",
	"tuan.ctrip.com",
	"you.ctrip.com",
	"g.ctrip.com",
	"lipin.ctrip.com",
	"ct.ctrip.com"
};

static void dns_async_client_result_callback(struct dns_item *list, int count) {
	int i = 0;

	for (i = 0;i < count;i ++) {
		printf("name:%s, ip:%s\n", list[i].domain, list[i].ip);
	}
}


int main(int argc, char *argv[]) {
#if 0
	dns_client_commit(argv[1]);
#else

	struct async_context *ctx = dns_async_client_init();
	if (ctx == NULL) return -2;

	int count = sizeof(domain) / sizeof(domain[0]);
	int i = 0;

	for (i = 0;i < count;i ++) {
		dns_async_client_commit(ctx, domain[i], dns_async_client_result_callback);
		//sleep(2);
	}

	getchar();
#endif
	
}

3、内存池

内存池主要是解决,频繁开辟和释放内存,造成的内存碎片问题,大量的内存碎片,会导致我们分配内存失败。
内存池是通过,申请比较大的内存块,后面慢慢的去使用他,避免重复申请和释放内存带来的效率消耗和大量内存碎片




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

#include <fcntl.h>



#define MP_ALIGNMENT       		32
#define MP_PAGE_SIZE			4096
#define MP_MAX_ALLOC_FROM_POOL	(MP_PAGE_SIZE-1)

#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))





struct mp_large_s {
	struct mp_large_s *next;
	void *alloc;
};

struct mp_node_s {

	unsigned char *last;
	unsigned char *end;
	
	struct mp_node_s *next;
	size_t failed;
};

struct mp_pool_s {

	size_t max;

	struct mp_node_s *current;
	struct mp_large_s *large;

	struct mp_node_s head[0];

};

struct mp_pool_s *mp_create_pool(size_t size);
void mp_destory_pool(struct mp_pool_s *pool);
void *mp_alloc(struct mp_pool_s *pool, size_t size);
void *mp_nalloc(struct mp_pool_s *pool, size_t size);
void *mp_calloc(struct mp_pool_s *pool, size_t size);
void mp_free(struct mp_pool_s *pool, void *p);


struct mp_pool_s *mp_create_pool(size_t size) {

	struct mp_pool_s *p;
	int ret = posix_memalign((void **)&p, MP_ALIGNMENT, size + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s));
	if (ret) {
		return NULL;
	}
	
	p->max = (size < MP_MAX_ALLOC_FROM_POOL) ? size : MP_MAX_ALLOC_FROM_POOL;
	p->current = p->head;
	p->large = NULL;

	p->head->last = (unsigned char *)p + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);
	p->head->end = p->head->last + size;

	p->head->failed = 0;

	return p;

}

void mp_destory_pool(struct mp_pool_s *pool) {

	struct mp_node_s *h, *n;
	struct mp_large_s *l;

	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			free(l->alloc);
		}
	}

	h = pool->head->next;

	while (h) {
		n = h->next;
		free(h);
		h = n;
	}

	free(pool);

}

void mp_reset_pool(struct mp_pool_s *pool) {

	struct mp_node_s *h;
	struct mp_large_s *l;

	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			free(l->alloc);
		}
	}

	pool->large = NULL;

	for (h = pool->head; h; h = h->next) {
		h->last = (unsigned char *)h + sizeof(struct mp_node_s);
	}

}

static void *mp_alloc_block(struct mp_pool_s *pool, size_t size) {

	unsigned char *m;
	struct mp_node_s *h = pool->head;
	size_t psize = (size_t)(h->end - (unsigned char *)h);
	
	int ret = posix_memalign((void **)&m, MP_ALIGNMENT, psize);
	if (ret) return NULL;

	struct mp_node_s *p, *new_node, *current;
	new_node = (struct mp_node_s*)m;

	new_node->end = m + psize;
	new_node->next = NULL;
	new_node->failed = 0;

	m += sizeof(struct mp_node_s);
	m = mp_align_ptr(m, MP_ALIGNMENT);
	new_node->last = m + size;

	current = pool->current;

	for (p = current; p->next; p = p->next) {
		if (p->failed++ > 4) {
			current = p->next;
		}
	}
	p->next = new_node;

	pool->current = current ? current : new_node;

	return m;

}

static void *mp_alloc_large(struct mp_pool_s *pool, size_t size) {

	void *p = malloc(size);
	if (p == NULL) return NULL;

	size_t n = 0;
	struct mp_large_s *large;
	for (large = pool->large; large; large = large->next) {
		if (large->alloc == NULL) {
			large->alloc = p;
			return p;
		}
		if (n ++ > 3) break;
	}

	large = mp_alloc(pool, sizeof(struct mp_large_s));
	if (large == NULL) {
		free(p);
		return NULL;
	}

	large->alloc = p;
	large->next = pool->large;
	pool->large = large;

	return p;
}

void *mp_memalign(struct mp_pool_s *pool, size_t size, size_t alignment) {

	void *p;
	
	int ret = posix_memalign(&p, alignment, size);
	if (ret) {
		return NULL;
	}

	struct mp_large_s *large = mp_alloc(pool, sizeof(struct mp_large_s));
	if (large == NULL) {
		free(p);
		return NULL;
	}

	large->alloc = p;
	large->next = pool->large;
	pool->large = large;

	return p;
}




void *mp_alloc(struct mp_pool_s *pool, size_t size) {

	unsigned char *m;
	struct mp_node_s *p;

	if (size <= pool->max) {

		p = pool->current;

		do {
			
			m = mp_align_ptr(p->last, MP_ALIGNMENT);
			if ((size_t)(p->end - m) >= size) {
				p->last = m + size;
				return m;
			}
			p = p->next;
		} while (p);

		return mp_alloc_block(pool, size);
	}

	return mp_alloc_large(pool, size);
	
}


void *mp_nalloc(struct mp_pool_s *pool, size_t size) {

	unsigned char *m;
	struct mp_node_s *p;

	if (size <= pool->max) {
		p = pool->current;

		do {
			m = p->last;
			if ((size_t)(p->end - m) >= size) {
				p->last = m+size;
				return m;
			}
			p = p->next;
		} while (p);

		return mp_alloc_block(pool, size);
	}

	return mp_alloc_large(pool, size);
	
}

void *mp_calloc(struct mp_pool_s *pool, size_t size) {

	void *p = mp_alloc(pool, size);
	if (p) {
		memset(p, 0, size);
	}

	return p;
	
}

void mp_free(struct mp_pool_s *pool, void *p) {

	struct mp_large_s *l;
	for (l = pool->large; l; l = l->next) {
		if (p == l->alloc) {
			free(l->alloc);
			l->alloc = NULL;

			return ;
		}
	}
	
}


int main(int argc, char *argv[]) {

	int size = 1 << 12;

	struct mp_pool_s *p = mp_create_pool(size);

	int i = 0;
	for (i = 0;i < 10;i ++) {

		void *mp = mp_alloc(p, 512);
//		mp_free(mp);
	}

	//printf("mp_create_pool: %ld\n", p->max);
	printf("mp_align(123, 32): %d, mp_align(17, 32): %d\n", mp_align(24, 32), mp_align(17, 32));
	//printf("mp_align_ptr(p->current, 32): %lx, p->current: %lx, mp_align(p->large, 32): %lx, p->large: %lx\n", mp_align_ptr(p->current, 32), p->current, mp_align_ptr(p->large, 32), p->large);

	int j = 0;
	for (i = 0;i < 5;i ++) {

		char *pp = mp_calloc(p, 32);
		for (j = 0;j < 32;j ++) {
			if (pp[j]) {
				printf("calloc wrong\n");
			}
			printf("calloc success\n");
		}
	}

	//printf("mp_reset_pool\n");

	for (i = 0;i < 5;i ++) {
		void *l = mp_alloc(p, 8192);
		mp_free(p, l);
	}

	mp_reset_pool(p);

	//printf("mp_destory_pool\n");
	for (i = 0;i < 58;i ++) {
		mp_alloc(p, 256);
	}

	mp_destory_pool(p);

	return 0;

}




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1028872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring事件机制之ApplicationEvent

博主介绍&#xff1a;✌全网粉丝4W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

vue3 - 前端 Vue 项目提交GitHub 使用Actions自动化部署

GitHub Demo 地址 在线预览 参考文章 使用GithubActions发布Vue网站到GithubPage 使用Github Actions将Vue项目部署到Github Pages 前端使用github pages 部署自己的网站 GitHub Actions自动化部署前端项目指南 前言 vue前端项目写好之后&#xff0c;想部署到线上通过在线地址…

中秋接月饼

hellow大家好&#xff0c;中秋佳节到了&#xff0c;欢乐度节的同时&#xff0c;技术也要跟上呀&#xff0c;这次我们通过canvas实现一个中秋接月饼的小游戏&#xff0c;三连不迷路哦~ 展示一下游戏成品&#xff1a; 准备游戏背景 首先我们将游戏背景界面绘制出来。 游戏背景…

滚雪球学Java(37):深入了解Java方法作用域和生命周期,让你写出更高效的代码

&#x1f3c6;本文收录于「滚雪球学Java」专栏&#xff0c;专业攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎大家关注&&收藏&#xff01;持续更新中&#xff0c;up&#xff01;up&#xff01;up&#xff01;&#xf…

微信重磅更新!有人已经涨粉好几万了!

公众号又更新了。 一个是发布功能升级&#xff0c;新发布的内容将展示在公众号主页&#xff0c;并有机会获得平台推荐。但仍然不会推送给用户&#xff0c;这是除了次数以外&#xff0c;和群发文章仅有的区别了。 ▲ 图片来源&#xff1a;微信公众号平台 不过目前仅支持用网页…

Android调用相机拍照,展示拍摄的图片

调用相机&#xff08;隐式调用&#xff09; //自定义一个请求码 这里我设为10010int TAKE_PHOTO_REQUEST 10010;int RESULT_CANCELED 0;//定义取消码//触发监听&#xff0c;调用相机image_camera.setOnClickListener(new View.OnClickListener() {Overridepublic void onCli…

Network: use `--host` to expose

vite 启动项目提示 Network: use --host to expose 同事不能通过本地IP地址访问项目 解决方案&#xff1a;package.json中启动命令配置本地IP地址 vite --host 192.168.200.252

windows11中安装curl

windows11中安装curl 1.下载curl curl 下载地址&#xff1a;curl 2.安装curl 2.1.解压下载的压缩包 解压文件到 C:\Program Files\curl-8.3.0_1-win64-mingw 目录 2.2.配置环境变量 WINS 可打开搜索栏&#xff0c;输入“编辑系统环境变量” 并按回车。 3.可能遇到的问题 3…

天地图绘制区域图层

背景&#xff1a; 业务方要求将 原效果图 参考效果图 最终实现效果 变更点&#xff1a; 1.将原有的高德地图改为天地图 2.呈现形式修改&#xff1a;加两层遮罩&#xff1a;半透明遮罩层mask区域覆盖物mask 实现过程&#xff1a; 1.更换地图引入源 <link rel"style…

BI系统上的报表怎么导出来?附方法步骤

在BI系统上做好的数据可视化分析报表&#xff0c;怎么导出来给别人看&#xff1f;方法有二&#xff0c;分别是1使用报表分享功能&#xff0c;2使用报表导出功能。下面就以奥威BI系统为例&#xff0c;简明扼要地介绍这两个功能。 1、报表分享功能 作用&#xff1a; 让其他同事…

SqlServer备份与还原 System.Data.SqlClient.SqlError: 媒体集有 2 个媒体簇,但只提供了 1 个。必须提供所有成员

System.Data.SqlClient.SqlError: 媒体集有 2 个媒体簇,但只提供了 1 个。必须提供所有成员。 (Microsoft.SqlServer.Smo) 这是由于你备份时&#xff0c;没有去掉默认的C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Backup\数据库名.bak&#xff0c;而又添加了一个新路…

【扩散生成模型】Diffusion Generative Models

提出扩散模型思想的论文&#xff1a; 《Deep Unsupervised Learning using Nonequilibrium Thermodynamics》理解 扩散模型综述&#xff1a; “扩散模型”首篇综述论文分类汇总&#xff0c;谷歌&北大最新研究 理论推导、代码实现&#xff1a; What are Diffusion Models?…

【办公小神器】:快速批量转换Word、Excel、PPT为PDF脚本!

文章目录 ✨哔哩吧啦✨脚本使用教程✨温馨小提示设置&#x1f4da;资源领取 专栏Python零基础入门篇&#x1f525;Python网络蜘蛛&#x1f525;Python数据分析Django基础入门宝典&#x1f525;小玩意儿&#x1f525;Web前端学习tkinter学习笔记Excel自动化处理 ✨哔哩吧啦 前…

Linux 安装 git

一 . 安装git 方式1&#xff1a;通过yum 安装 yum -y install git查看是否安装成功 git --version安装目录在&#xff1a;/usr/libexec/git-core yum 安装有一些缺点 &#xff1a;不能自己指定安装目录、安装版本 方式 2 下载tar.gz 包 配置 查看git 版本&#xff1a;Index…

windows11专业版下安装ubuntu20终端应用

主要步骤如下&#xff1a; https://blog.csdn.net/i_ziyu/article/details/127603934 https://blog.csdn.net/qq_17525509/article/details/122287051 搜索windows功能&#xff1a; 在设置里面&#xff1a; 设置–更新和安全–开发者选项 打开开发者模式。 去应用商店下载&a…

ChatGPT实战-构建文章分析AI聊天机器人

视频版本&#xff1a; ChatGPT实战-构建文章分析AI聊天机器人 简介 本文实现如下功能&#xff1a; 当浏览一篇文章&#xff0c;点击分享&#xff0c;分享到聊天软件的对话框中。它就会生成一个文章的总结和分析结果。例如分析是否有逻辑问题&#xff0c;是否有诱导购买&#…

基于SSM+Vue的在线购书商城系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

浅谈 React 与 Vue 更新机制的差异

前言 哈喽&#xff0c;大家好&#xff0c;我是 Baker &#xff01;&#x1f389; 对于前端的 Vue 和 React 相信大家并不陌生&#xff0c;这两个库有着截然不同的设计思想和发展目标&#xff0c;对于我们上层使用者来说&#xff0c;研究它们的差异不仅让我们更加深入的去理解…

使用自定义插槽(slot)来将数据传递给插槽内容。el-step

description为描述性文字&#xff0c;需使用slot来自定义文字。 A 是 Vue 3 中的语法糖&#xff0c;用于简洁地定义插槽。用来绑定step组件中description。step可使用插槽 B是绑定date数据实现自定义描述文字。

VoxWeekly|The Sandbox 生态周报|20230918

欢迎来到由 The Sandbox 发布的《VoxWeekly》。我们会在每周发布&#xff0c;对上一周 The Sandbox 生态系统所发生的事情进行总结。 如果你喜欢我们内容&#xff0c;欢迎与朋友和家人分享。请订阅我们的 Medium 、关注我们的 Twitter&#xff0c;并加入 Discord 社区&#xf…