EasyDarwin 中使用epoll网络模型替换原来的select模型

EasyDarwin是由国内开源流媒体团队维护的一款开源流媒体平台框架,在DSS基础上进行的开发。从2012年12月创建并发展至今,从原有的单服务的流媒体服务器形式,扩展成现在的云平台架构的开源项目,更好地帮助广大流媒体开发者和创业型企业快速构建流媒体服务平台。

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;
}
#endif
1.启动服务器调用StartServer时会执行::epollInit()

2.调用EventContext::RequestEvent注册IO网络事件时会执行addEpollEvent(&fEventReq, theMask)

3.事件监听线程执行EventThread::Entry()时,调用epoll_waitevent(&theCurrentEvent, NULL)阻塞等待注册的IO事件发生
4.EventContext::Cleanup()执行时会调用deleteEpollEvent(int& fd)清除注册的IO网络事件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
最近在开发im服务器 需要大并发链接 QT默认的是使用select模型的 这种轮询方式非常慢 在高并发连接 我们需要epoll才能发挥linux服务器的性能 而且使用简单 整个服务端代码架构无需修改 直接可以使用 只要在 main文件添加: int main int argc char argv[] { #ifdef Q OS LINUX QCoreApplication::setEventDispatcher new EventDispatcherLibEvent ; qInstallMessageHandler customMessageHandler ; #endif QCoreApplication a argc argv ; auto ser new ConfigServer; ser >startServer ; return a exec ; } 在 pro文件添加 linux{ LIBS + levent core SOURCES + common eventdispatcher libevent eventdispatcher libevent cpp common eventdispatcher libevent eventdispatcher libevent config cpp common eventdispatcher libevent eventdispatcher libevent p cpp common eventdispatcher libevent socknot p cpp common eventdispatcher libevent tco eventfd cpp common eventdispatcher libevent tco pipe cpp common eventdispatcher libevent tco cpp common eventdispatcher libevent timers p cpp HEADERS + common eventdispatcher libevent common h common eventdispatcher libevent eventdispatcher libevent h common eventdispatcher libevent eventdispatcher libevent config h common eventdispatcher libevent eventdispatcher libevent config p h common eventdispatcher libevent eventdispatcher libevent p h common eventdispatcher libevent libevent2 emul h common eventdispatcher libevent qt4compat h common eventdispatcher libevent tco h common eventdispatcher libevent wsainit h } 可以直接跨平台了使用了 csdn博客:http: blog csdn net rushroom">最近在开发im服务器 需要大并发链接 QT默认的是使用select模型的 这种轮询方式非常慢 在高并发连接 我们需要epoll才能发挥linux服务器的性能 而且使用简单 整个服务端代码架构无需修改 直接可以使用 只要在 main文件添加: [更多]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值