加入线程池的http服务器

来源:互联网 发布:mit公开课 算法导论 编辑:程序博客网 时间:2024/05/30 04:06

      自己写了一个线程池,想把它和http服务连在一起,居然也不难。

      http的内容在另一篇文章《简易http服务器》中贴出了,我把它做成了三个文件,httpd.c和httpd.h,只需调用httpsvr(client_sock)即可;我在《unix环境线程编程练习》里贴出了线程池和使用方法。

先把httpd的调用放到线程的“任务”函数里:

void work(void *arg){int sock = (int)arg;httpsvr(sock);close(sock);}

然后与《简易http服务器》中svrthread.c的类似,只是去掉 void* svrthread(void *p) ,在listen()调用之后,就创建线程池:

th_pool_str tpool;if (init_tpool(&tpool, 8)){close(lsock);_exit(1);}

在循环内部,去掉创建线程的代码,替换成一句:

submit_task(&tpool, work, (void *)clientfd);

完整的代码是:

//svrtpool.c#include <stdio.h>#include <unistd.h>#include <pthread.h>#include <netinet/in.h>#include "httpd.h"#include "threadpool.h"//typedef struct sockaddr_in sockaddr_in;//typedef struct sockaddr sockaddr;#define PORT80#define BACKLOG5void work(void *arg){int sock = (int)arg;httpsvr(sock);close(sock);}int main(){int lsock,clientfd;lsock = socket(AF_INET,SOCK_STREAM,0);if (-1 == lsock){perror("socket error!\n");_exit(1);}int sockopt_on = 1;if (setsockopt(lsock,SOL_SOCKET,SO_REUSEADDR,&sockopt_on,sizeof(sockopt_on))){perror("setsockopet error\n");}sockaddr_in host_addr;host_addr.sin_family = AF_INET;host_addr.sin_port = htons(PORT);host_addr.sin_addr.s_addr = htonl(INADDR_ANY);if (-1 == bind(lsock, (sockaddr *)&host_addr, sizeof(sockaddr_in))){close(lsock);perror("bind error!\n");exit(1);}if (-1 == listen(lsock,BACKLOG)){close(lsock);perror("listen error!\n");_exit(1);}th_pool_str tpool;if (init_tpool(&tpool, 8)){close(lsock);_exit(1);}printf("server start on: %d\n",PORT);sockaddr_in addr;pthread_t svr_id;int size_addr = sizeof(addr),ret;for ( ; ; ){clientfd = accept(lsock,(sockaddr*)&addr,(socklen_t *)&size_addr);if (-1 == clientfd){perror("accept error!\n");continue;}submit_task(&tpool, work, (void *)clientfd);}close_tpool(&tpool);return 0;}
系统创建和销毁线程的消耗比较费时,在访问量上升到一定数量是,效率就会明显下降;用线程池省去了这些消耗,随着访问数量增加效率,比之前的程序也愈来愈明显。

现在看来线程池早就不是新技术了,很多服务器内部其实都用了线程池,比如数据库系统和各种知名的web服务器。



0 0
原创粉丝点击