epoll+thread pool 服务器简单实例
来源:互联网 发布:中点画圆算法流程图 编辑:程序博客网 时间:2024/05/17 10:40
服务器首先必须有一个监听套接字,然后用epoll去监听这个套接字,如果有连接到来,调用accept函数接受此连接,然后将此连接的套接字描述符传递到消息队列中,然后线程池检查消息队列,有任务,激活线程池中的一个线程,执行此任务。上述为我们服务器的基本的流程,下面具体的是实现。首先先介绍几个包裹函数,也就是socket,bind,listen和accept函数的包裹函数,里面只是添加了一些错误处理。
int Socket_t(){ int fd=socket(AF_INET,SOCK_STREAM,0); if(fd==-1) { perror("The socket func error : "); exit(1); } return fd;}
该函数返回一个TCP流套接字,正确执行,返回一个套接字描述符。
void Bind(int fd,const struct sockaddr_in * saddr,socklen_t len){ int num=bind(fd,(struct sockaddr*)saddr,len); if(num==-1) perror("The bind func error : ");}
Bind函数完成绑定工作,参数分别为套接字描述符,ipv4地址以及地址长度。该函数无返回值,出错打印错误信息。
void Listen(int fd,int backlog){ int num=listen(fd,backlog); if(num==-1) perror("The listen func error : ");}
此函数参数和listen函数完全相同,完成监听工作。
int Accept(int fd){ int num=accept(fd,NULL,NULL); if(num==-1) { perror("The accept func error : "); exit(1); } return num;}
接受一个连接,并返回一个该连接的套接字描述符。
void non_blocking(int fd){ int flags; flags=fcntl(fd,F_GETFL,0); flags |=O_NONBLOCK; fcntl(fd,F_SETFL,flags);}
这个函数将指定的描述符模式改为非阻塞模式。我们的服务器需要一个消息队列,而C语言没有C++现成的queue模板来使用,需要我们自己来写一个。我写的一个比较简单的队列来充当消息队列。
#define MAX_LINK 20typedef struct Queue{ int start; int end; int fd[MAX_LINK];}Queue;
上面为我们队列的结构体,其中start代表队列尾,end代表队列头,我用的是数组实现的一个循环队列。其中数组大小为20下面是一些对应的队列的操作。
void queue_init(Queue *queue)//队列初始化{ queue->start=0; queue->end=0; int i=0; bzero(queue->fd,sizeof(queue->fd));}void queue_add(Queue*queue,int fd)//队列添加数据{ int n=(queue->start+1)%MAX_LINK; if(n==queue->end) { printf("The queue was filled\n"); return; } else { queue->start=n; queue->fd[queue->start]=fd; }}int queue_pop(Queue *queue)//队列弹出一个数据{ if(queue->end==queue->start) { printf("The queue is empty\n"); return -1; } else { queue->end=(queue->end+1)%MAX_LINK; return queue->fd[queue->end]; }}int queue_size(Queue*queue)//队列当前大小{ return queue->start-queue->end;}
有了队列之后,我们还需要一个线程池。下面为线程池的操作和结构。
#define MAX_P_NUM 3typedef struct Pool{ pthread_mutex_t mutex; pthread_cond_t cond; pthread_t pid[MAX_P_NUM]; Queue *queue;}Pool;
上面为线程池的结构体,mutex和cond分别为互斥锁和条件变量,MAX_P_NUM代表线程池所拥有的总线程数,queue代表消息队列。
void pool_init(Pool*pool,Queue*queue)//线程初始化{ pthread_mutex_init(&pool->mutex,NULL); pthread_cond_init(&pool->cond,NULL); bzero(pool->pid,sizeof(pool->pid)); pool->now_work=0; pool->queue=queue; int i=0; for(i=0;i<MAX_P_NUM;i++) { int err=pthread_create(&(pool->pid[i]),NULL,p_func,(void*)pool); if(err!=0) { fprintf(stderr,"The Thread %d create failed\n",i); return; } }}void pool_addw(Pool* pool,int fd)//线程池中增加任务{ queue_add(pool->queue,fd); pthread_cond_signal(&(pool->cond));}void *p_func(void *arg) //线程处理函数{ Pool *pool=(Pool*)arg; while(1) { while(queue_size(pool->queue)==0) { pthread_mutex_lock(&(pool->mutex)); pthread_cond_wait(&(pool->cond),&(pool->mutex)); } int fd=queue_pop(pool->queue); pthread_mutex_unlock(&(pool->mutex)); char rbuf[20]; bzero(rbuf,sizeof(rbuf)); while(recv(fd,rbuf,sizeof(rbuf),0)!=0) { printf("%lx recv string %s\n",pthread_self(),rbuf); bzero(rbuf,sizeof(rbuf)); } }}
以上就是我们的准备工作,下面就是服务器的代码。
#include<sys/socket.h>#include<sys/types.h>#include<arpa/inet.h>#include<stdlib.h>#include<stdio.h>#include<assert.h>#include<errno.h>#include<string.h>#include<fcntl.h>#include<sys/epoll.h>#include<unistd.h>#include<signal.h>#include"Queue.h"#include"Pool.h"Queue queue; //消息队列Pool pool; //线程池int main(int argc,char **argv){ queue_init(&queue); //消息队列初始化 pool_init(&pool,&queue); //线程池初始化 struct sockaddr_in seraddr; int lisfd,confd; seraddr.sin_family=AF_INET; seraddr.sin_port=htons(6000); seraddr.sin_addr.s_addr=htonl(INADDR_ANY); lisfd=Socket_t(); assert(lisfd>0); Bind(lisfd,&seraddr,sizeof(seraddr)); Listen(lisfd,5); non_blocking(lisfd); //到这里我们的监听套接字创建完毕 signal(SIGPIPE,SIG_IGN);//让系统忽略SIGPIPE信号 int efd=epoll_create(50);// assert(efd>0); struct epoll_event ev; ev.data.fd=lisfd; ev.events=EPOLLIN | EPOLLET; int ctl_num=epoll_ctl(efd,EPOLL_CTL_ADD,lisfd,&ev); struct epoll_event rev[20]; while(1) { bzero(rev,sizeof(rev)); int n=epoll_wait(efd,rev,20,-1); int i; for(i=0;i<n;i++) { if(rev[i].data.fd==lisfd) { confd=Accept(lisfd); printf("the confd is %d\n",confd); if(confd>0) pool_addw(&pool,confd); } } } return 0;}
客户端代码这里就不再贴出来了,客户端每隔一秒发送一个"hello"字符串,服务器接收并打印他。
0 0
- epoll+thread pool 服务器简单实例
- 服务器epoll+thread pool模型
- 简单实现thread pool
- smart thread pool 【1】简单的使用
- Thread Pool
- Thread Pool
- Thread Pool
- thread pool
- thread pool
- thread pool
- thread pool
- Thread Pool
- thread pool
- Thread Pool
- Thread pool
- Linux epoll机制简单实例
- epoll实现简单echo服务器
- JAVA 多线程Thread简单实例
- POJ2063 Investment(完全背包)
- 装饰者模式
- Android Support Library 23.2.0 Toolbar图标变黑
- Android界面性能调优(转载记录)
- python的dict,set,list,tuple简单分析 老搞混
- epoll+thread pool 服务器简单实例
- 一个ListView根据标识加载不同布局,很简单的例子,就是聊天界面,你说话在右边好友在左边怎么实现呢.
- 教大家简单鉴别高仿三星s6山寨s6屏幕cpu字库主板维修mtk6735等
- iOS9中如何在日历App中创建一个任意时间之前开始的提醒(三)
- 欢迎使用CSDN-markdown编辑器
- 用户系统
- hdu 5643 BestCoder Round #75
- 各种排序算法的时间复杂度
- [Chromium中文文档]Chromium多进程架构