EasyDarwin 中使用epoll网络模型替换原来的select模型
2017-11-22 21:12
381 查看
EasyDarwin是由国内开源流媒体团队维护的一款开源流媒体平台框架,在DSS基础上进行的开发。从2012年12月创建并发展至今,从原有的单服务的流媒体服务器形式,扩展成现在的云平台架构的开源项目,更好地帮助广大流媒体开发者和创业型企业快速构建流媒体服务平台。
DSS中使用select监听网络IO事件,由于select最大只支持1024个文件描述符,原因#define __FD_SETSIZE 1024,随着使用的fd增加,处理性能上也会下降;easy darwin对此进行了改进。
下面是easydarwin中epoll的封装
2.调用EventContext::RequestEvent注册IO网络事件时会执行addEpollEvent(&fEventReq, theMask)
3.事件监听线程执行EventThread::Entry()时,调用epoll_waitevent(&theCurrentEvent, NULL)阻塞等待注册的IO事件发生
4.EventContext::Cleanup()执行时会调用deleteEpollEvent(int& fd)清除注册的IO网络事件
DSS中使用select监听网络IO事件,由于select最大只支持1024个文件描述符,原因#define __FD_SETSIZE 1024,随着使用的fd增加,处理性能上也会下降;easy darwin对此进行了改进。
下面是easydarwin中epoll的封装
#include "epollEvent.h" #include <sys/errno.h> #include <sys/time.h> #include <map> #include "OSMutex.h" using namespace std; #if defined(__linux__) #define MAX_EPOLL_FD 20000 static int epollfd = 0; //epoll 描述符 static epoll_event* _events = NULL; //epoll事件接收数组 static int m_curEventReadPos = 0; //当前读事件位置,在epoll事件数组中的位置 static int m_curTotalEvents = 0; //总的事件个数,每次epoll_wait之后更新 static OSMutex sMaxFDPosMutex; //锁 static bool canEpoll = false; //是否可以执行epoll_wait,避免频繁执行,浪费CPU static map<int ,void *> epollFdmap;//映射 fd和对应的RTSPSession对象 /* 函数名:epollInit 功能:初始化epoll,创建epollfd,申请epoll事件接收内存 */ int epollInit() { epollfd = epoll_create(MAX_EPOLL_FD); if(_events == NULL) { _events = new epoll_event[MAX_EPOLL_FD];//we only listen the read event } if(_events == NULL) { perror("new epoll_event error:"); exit(1); } m_curEventReadPos = 0; m_curTotalEvents = 0; return 0; } /* 函数名:addEpollEvent 功能:增加一个epoll监听事件,参数1 请求结构 参数2 事件类型 */ int addEpollEvent(struct eventreq *req,int event) { if(req == NULL) { return -1; } struct epoll_event ev; memset(&ev,0x0,sizeof(ev)); int ret = -1; OSMutexLocker locker(&sMaxFDPosMutex);//加锁,防止线程池中的多个线程执行该函数,导致插入监听事件失败 if(event == EV_RE) { ev.data.fd = req->er_handle; ev.events = EPOLLIN|EPOLLHUP|EPOLLERR;//level triggle ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,req->er_handle,&ev); } else if(event == EV_WR) { ev.data.fd = req->er_handle; ev.events = EPOLLOUT;//level triggle ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,req->er_handle,&ev); } else if(event == EV_RM) { ret = epoll_ctl(epollfd,EPOLL_CTL_DEL,req->er_handle,NULL);//remove all this fd events } else//epoll can not listen RESET {//we dont needed } epollFdmap[req->er_handle] = req->er_data; canEpoll = true;//每次新增事件后可以马上执行epoll_wait,新增了监听事件,意味着接下来可能马上要发生事件在这个fd上 return 0; } /* 函数名:deleteEpollEvent 功能:删除一个epoll监听事件,参数1 要删除的fd */ int deleteEpollEvent(int& fd) { int ret = -1; OSMutexLocker locker(&sMaxFDPosMutex); ret = epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,NULL);//remove all this fd events canEpoll = true;//每删除一个fd后,可以马上执行epoll_wait,可能在删除掉的fd上出现读异常 return 0; } /* 函数名:epollwaitevent 功能:等待epoll监听事件,返回事件个数 */ int epollwaitevent() { if(canEpoll == false) { return -1; } int nfds = 0; int curreadPos = -1;//m_curEventReadPos;//start from 0 if(m_curTotalEvents <= 0)//当前一个epoll事件都没有的时候,执行epoll_wait { m_curTotalEvents = 0; m_curEventReadPos = 0; nfds = epoll_wait(epollfd,_events,MAX_EPOLL_FD,15000); if(nfds > 0) { canEpoll = false;//wait到了epoll事件,先处理完再wait m_curTotalEvents = nfds; } else if(nfds < 0) { } else if(nfds == 0) { canEpoll = true;//这一次wait超时了,下一次继续wait } } if(m_curTotalEvents)//从事件数组中每次取一个,取的位置通过m_curEventReadPos设置 { curreadPos = m_curEventReadPos; m_curEventReadPos ++; if(m_curEventReadPos >= m_curTotalEvents - 1) { m_curEventReadPos = 0; m_curTotalEvents = 0; } } return curreadPos; } /* 函数名:epoll_waitevent 功能:等待一个epoll监听事件,返回一个事件,参数1:返回事件的指针 参数2 忽略 */ int epoll_waitevent(struct eventreq *req, void* onlyForMOSX) { int eventPos = -1; eventPos = epollwaitevent(); if(eventPos >= 0) { req->er_handle = _events[eventPos].data.fd; if(_events[eventPos].events == EPOLLIN|| _events[eventPos].events == EPOLLHUP|| _events[eventPos].events == EPOLLERR) { req->er_eventbits = EV_RE;//we only support read event } else if(_events[eventPos].events == EPOLLOUT) { req->er_eventbits = EV_WR; } req->er_data = epollFdmap[req->er_handle]; OSMutexLocker locker(&sMaxFDPosMutex); deleteEpollEvent(req->er_handle); return 0; } return EINTR; } /* 函数名:epollDestory 功能:销毁epoll,析构的时候 */ int epollDestory() { delete[] _events; return 0; } #endif1.启动服务器调用StartServer时会执行::epollInit()
2.调用EventContext::RequestEvent注册IO网络事件时会执行addEpollEvent(&fEventReq, theMask)
3.事件监听线程执行EventThread::Entry()时,调用epoll_waitevent(&theCurrentEvent, NULL)阻塞等待注册的IO事件发生
4.EventContext::Cleanup()执行时会调用deleteEpollEvent(int& fd)清除注册的IO网络事件
相关文章推荐
- libevent for qt网络模块,直接替换qt的select模型,支持epoll,select,pool.使用非常简单,无需修改以前的代码结构
- Linux网络编程--使用epoll模型同时处理tcp和udp服务
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型
- 网络编程基础:使用SELECT模型
- Linux下I/O多路复用select, poll, epoll 三种模型的Python使用
- Linux网络通信编程(套接字模型TCP\UDP与IO多路复用模型select\poll\epoll)
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型
- 网络I/O模型select/poll/epoll
- linux中使用select和epoll确定异步connect连接是否成功 标签: 网络编程服务器异步connectSO_ERRORsocket 2016-07-31 23:07 1008人阅读 评
- 浅谈网络I/O多路复用模型 select & poll & epoll
- 使用socket实现基于select模型的网络聊天室
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型
- 几种典型的服务器网络编程模型归纳( select poll epoll)
- select和epoll网络模型
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较
- python实现select和epoll模型socket网络编程
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型
- 浅谈网络I/O多路复用模型 select & poll & epoll