最近比较忙,好久没更新了;今天我们看一下事件的监听方式,在linux下面事件的监听方式有三种select、poll、epoll,性能上面epoll最高,如果仅是最多监听十多个描述符,用啥无所谓,如果是几千个呢就非epoll不能胜任了。

对三种时间监听方式进行封装,由于行为相似因此都继承于一个抽象基类EventDispatcher;SelectDispatcher:使用select方式监听,PollDispatcher:使用poll方式监听,EpollDispatcher:使用epoll方式监听。

/***************************************************************************************
****************************************************************************************
* FILE  : event_dispatcher.h
* Description :
*    
* Copyright (c) 2012 by Liu Yanyun(E-mail:liuyun827@foxmail.com). All Rights Reserved.
*            Without permission, shall not be used for any commercial purpose
*
* History:
* Version  Name         Date   Description
   0.1  Liu Yanyun  2012/12/20  Initial Version
  
****************************************************************************************
****************************************************************************************/

#ifndef _EVENT_DISPATCHER_H_
#define _EVENT_DISPATCHER_H_

#include <map>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "sock_ev.h"
#include "event_loop.h"

class Socket;
class EventLoop;

typedef std::vector<struct pollfd> PollFdVecT;

/*==================================================================
* Function : EventDispatcher
* Description : event dispatcher base class
==================================================================*/
class EventDispatcher
{
public:

/*==================================================================
  * Function : EventDispatcher.EventDispatcher
  * Description : construction function
  ==================================================================*/
  EventDispatcher();
 
  /*==================================================================
  * Function : EventDispatcher.~EventDispatcher
  * Description : Destructor function
  ==================================================================*/
  virtual ~EventDispatcher();
 
  /*==================================================================
  * Function : EventDispatcher.initialize
  * Description : implement by subclass
  * Return Value: initialize success return true,or else return false
  ==================================================================*/
  virtual bool initialize() = 0;
 
  /*==================================================================
  * Function : EventDispatcher.addEvt
  * Description : add an event and register callback
  * Input Para :
  * Output Para :
  * Return Value: success return true,or else return false
  ==================================================================*/
  virtual bool addEvt(EventLoop *loop_,
      Socket *sock_,
      EvCallBack cb_,
      EventType evt_,
      void *arg_) = 0;
     
  /*==================================================================
  * Function : EventDispatcher.removeEvt
  * Description : remove an event and un-register callback
  * Input Para :
  * Output Para :
  * Return Value: success return true,or else return false
  ==================================================================*/
  virtual bool removeEvt(Socket *sock_,
      EventType evt_) = 0;
  /*==================================================================
  * Function : EventDispatcher.listen
  * Description : wait for event trigger
  * Input Para :
  * Output Para :
  * Return Value:
  ==================================================================*/
  virtual int listen(SockMapT &sockMap_,
      int timeout_) = 0;
};

/*==================================================================
* Function : SelectDispatcher
* Description : use select for wait event
==================================================================*/
class SelectDispatcher : public EventDispatcher
{
public:

/*==================================================================
  * Function : SelectDispatcher.SelectDispatcher
  * Description : construction function
  ==================================================================*/
  SelectDispatcher();

/*==================================================================
  * Function : SelectDispatcher.~SelectDispatcher
  * Description : Destructor function
  ==================================================================*/
  virtual ~SelectDispatcher();

/*==================================================================
  * Function : initialize
  * Description : Please reference to parent class
  ==================================================================*/
  bool initialize();

/*==================================================================
  * Function : addEvt
  * Description : Please reference to parent class
  ==================================================================*/
  bool addEvt(EventLoop *loop_,
      Socket *sock_,
      EvCallBack cb_,
      EventType evt_,
      void *arg_);

/*==================================================================
  * Function : removeEvt
  * Description : Please reference to parent class
  ==================================================================*/
  bool removeEvt(Socket *sock_,
      EventType evt_);

/*==================================================================
  * Function : listen
  * Description : Please reference to parent class
  ==================================================================*/
  int listen(SockMapT &sockMap_,
      int timeout_);
     
private:
 
  fd_set   readSet;
  fd_set   writeSet;
  fd_set   exceptSet;
};

/*==================================================================
* Function : PollDispatcher
* Description : use poll for wait event
==================================================================*/
class PollDispatcher : public EventDispatcher
{
public:

/*==================================================================
  * Function : PollDispatcher.PollDispatcher
  * Description : construction function
  ==================================================================*/
  PollDispatcher();

/*==================================================================
  * Function : PollDispatcher.~PollDispatcher
  * Description : Destructor function
  ==================================================================*/
  virtual ~PollDispatcher();

/*==================================================================
  * Function : PollDispatcher.getPos
  * Description : get position in the vector by fd
  * Input Para : socket fd
  * Return Value: position in the vector
  ==================================================================*/
  PollFdVecT::iterator getPos(int fd_);

/*==================================================================
  * Function : initialize
  * Description : Please reference to parent class
  ==================================================================*/
  bool initialize();

/*==================================================================
  * Function : addEvt
  * Description : Please reference to parent class
  ==================================================================*/
  bool addEvt(EventLoop *loop_,
      Socket *sock_,
      EvCallBack cb_,
      EventType evt_,
      void *arg_);

/*==================================================================
  * Function : removeEvt
  * Description : Please reference to parent class
  ==================================================================*/
  bool removeEvt(Socket *sock_,
      EventType evt_);

/*==================================================================
  * Function : listen
  * Description : Please reference to parent class
  ==================================================================*/
  int listen(SockMapT &sockMap_,
      int timeout_);

private:

PollFdVecT pollFds;
};

/*==================================================================
* Function : EpollDispatcher
* Description : use epoll for wait event
==================================================================*/
class EpollDispatcher : public EventDispatcher
{
public:

/*==================================================================
  * Function : EpollDispatcher.EpollDispatcher
  * Description : construction function
  ==================================================================*/
  EpollDispatcher();

/*==================================================================
  * Function : EpollDispatcher.~EpollDispatcher
  * Description : Destructor function
  ==================================================================*/
  virtual ~EpollDispatcher();

/*==================================================================
  * Function : initialize
  * Description : Please reference to parent class
  ==================================================================*/
  bool initialize();

/*==================================================================
  * Function : addEvt
  * Description : Please reference to parent class
  ==================================================================*/
  bool addEvt(EventLoop *loop_,
      Socket *sock_,
      EvCallBack cb_,
      EventType evt_,
      void *arg_);

/*==================================================================
  * Function : removeEvt
  * Description : Please reference to parent class
  ==================================================================*/
  bool removeEvt(Socket *sock_,
      EventType evt_);

/*==================================================================
  * Function : listen
  * Description : Please reference to parent class
  ==================================================================*/
  int listen(SockMapT &sockMap_,
      int timeout_);
     
private:

int  epollFd;
};

#endif /*_EVENT_DISPATCHER_H_*/

下面是实现文件:

#include "socket.h"
#include "event_dispatcher.h"
#include "sock_ev.h"
#include <errno.h>

EventDispatcher::EventDispatcher()
{
  //do nothing
}

EventDispatcher::~EventDispatcher()
{
  //do nothing
}
SelectDispatcher::SelectDispatcher()
{
  FD_ZERO(&readSet);
  FD_ZERO(&writeSet);
  FD_ZERO(&exceptSet);
}

SelectDispatcher::~SelectDispatcher()
{
}

bool SelectDispatcher::initialize()
{
  return true;
}

bool SelectDispatcher::addEvt(EventLoop *loop_,
    Socket *sock_,
    EvCallBack cb_,
    EventType evt_,
    void *arg_)
{
  if(evt_ & evRead)
  {
    FD_SET(sock_->getFd(), &readSet);
  }
 
  if(evt_ & evWrite)
  {
    FD_SET(sock_->getFd(), &writeSet);
  }
 
  if(evt_ & evError)
  {
    FD_SET(sock_->getFd(), &exceptSet);
  }
 
  sock_->setCallBack(loop_, cb_, evt_, arg_);
 
  return true;
}

bool SelectDispatcher::removeEvt(Socket *sock_,
    EventType evt_)
{
  sock_->clearCallBack(evt_);
 
  if(evt_ & evRead)
  {
    FD_CLR(sock_->getFd(), &readSet);
  }
 
  if(evt_ & evWrite)
  {
    FD_CLR(sock_->getFd(), &writeSet);
  }
 
  if(evt_ & evError)
  {
    FD_CLR(sock_->getFd(), &exceptSet);
  }

return true;
}

int SelectDispatcher::listen(SockMapT &sockMap_,
    int timeout_)
{
  timeval  timeout;
  timeout.tv_sec = timeout_/1000;
  timeout.tv_usec = timeout_ % 1000 * 1000;

fd_set tmpReadSet = readSet;
  fd_set tmpWriteSet = writeSet;

int maxFd = sockMap_.rbegin()->first;
  int num = select(maxFd + 1, &tmpReadSet, &tmpWriteSet, NULL,
                    (timeout_ >=0) ? (&timeout):NULL);
  if (num <= 0)
  {
    logTrace("num=%d;size:%d;%m", num, sockMap_.size());
    return num;
  }

SockMapT::iterator it = sockMap_.begin();
  while (it != sockMap_.end())
  {
    SockMapT::iterator tmpIt = it++;
    if(FD_ISSET(tmpIt->first, &tmpReadSet))
    {
      tmpIt->second->processEvent(evRead);
    }
   
    if(FD_ISSET(tmpIt->first, &tmpWriteSet))
    {
      tmpIt->second->processEvent(evWrite);
    }
  }
 
  return num;
}

PollDispatcher::PollDispatcher()
{
  //do nothing
}

PollDispatcher::~PollDispatcher()
{
  pollFds.clear();
}

PollFdVecT::iterator PollDispatcher::getPos(int fd_)
{
  PollFdVecT::iterator it;
  for(it = pollFds.begin(); it != pollFds.end(); it++)
  {
    if(it->fd == fd_)
    {
      return it;
    }
  }

return it;
}
bool PollDispatcher::initialize()
{
  return true;
}

bool PollDispatcher::addEvt(EventLoop *loop_,
    Socket *sock_,
    EvCallBack cb_,
    EventType evt_,
    void *arg_)
{
  struct pollfd pfd;
  memset(&pfd, 0, sizeof(pfd));

pfd.fd = sock_->getFd();
  PollFdVecT::iterator it = getPos(pfd.fd);
  if(it == pollFds.end())
  {
    if(evt_ & evRead)
    {
      pfd.events |= POLLIN;
    }
   
    if(evt_ & evWrite)
    {
      pfd.events |= POLLOUT;
    }
    pollFds.push_back(pfd);
  }
  else
  {
    if(evt_ & evRead)
    {
      it->events |= POLLIN;
    }
   
    if(evt_ & evWrite)
    {
      it->events |= POLLOUT;
    }
  }

sock_->setCallBack(loop_, cb_, evt_, arg_);
 
  return true;
}

bool PollDispatcher::removeEvt(Socket *sock_,
    EventType evt_)
{
  sock_->clearCallBack(evt_);
 
  PollFdVecT::iterator it = getPos(sock_->getFd());
  if(it == pollFds.end())
  {
    logTrace("can't find this in poll event vector");
    return false;
  }
  else
  {
    EventType evt = ~evt_&sock_->getEvt();
    if(0 == evt)
    {
      pollFds.erase(it);
      return true;
    }
 
    if(evt & evRead)
    {
      it->events |= POLLIN;
    }
   
    if(evt & evWrite)
    {
      it->events |= POLLOUT;
    }
  }
 
  return true;
}

int PollDispatcher::listen(SockMapT &sockMap_,
    int timeout)
{
  int num = poll(&pollFds[0], pollFds.size(), timeout);
  if(num <= 0)
  {
    logTrace("num=%d;size:%d;%m", num, sockMap_.size());
    return num;
  }

uint32_t index = 0;
  for(index = 0; index < pollFds.size(); index++)
  {
    struct pollfd pfd = pollFds[index];
    SockMapT::iterator mapIt = sockMap_.find(pfd.fd);
    if(mapIt == sockMap_.end())
    {
      logTrace("can't find this fd in map");
      continue;
    }
 
    if(pfd.revents & POLLIN)
    {
      mapIt->second->processEvent(evRead);
    }
   
    if(pfd.revents & POLLOUT)
    {
      mapIt->second->processEvent(evWrite);
    }
  }
 
  return num;
}

EpollDispatcher::EpollDispatcher()
{
  epollFd = -1;
}

/// 析构函数
EpollDispatcher::~EpollDispatcher()
{
  close(epollFd);
}
bool EpollDispatcher::initialize()
{
  epollFd = epoll_create(256);
  if(-1 == epollFd)
  {
    logTrace("epoll_create failed;%m");
    return false;
  }
  return true;
}

bool EpollDispatcher::addEvt(EventLoop *loop_,
    Socket *sock_,
    EvCallBack cb_,
    EventType evt_,
    void *arg_)
{
  epoll_event epEvt;
  memset(&epEvt, 0, sizeof(epEvt));
  epEvt.data.fd = sock_->getFd();
 
  EventType evt = evt_|sock_->getEvt();
  if(evt & evRead)
  {
    epEvt.events |= EPOLLIN;
  }
 
  if (evt & evWrite)
  {
    epEvt.events |= EPOLLOUT;
  }

if(epoll_ctl(epollFd, EPOLL_CTL_MOD, sock_->getFd(), &epEvt) != 0)
  {
    if(errno == ENOENT)
    {
      if(epoll_ctl(epollFd, EPOLL_CTL_ADD, sock_->getFd(), &epEvt) != 0)
      {
        logTrace("epoll_ctl(EPOLL_CTL_ADD) failed,%m");
        return false;
      }
    }
    else
    {
      logTrace("epoll_ctl(EPOLL_CTL_MOD) failed,%m");
      return false;
    }
  }

sock_->setCallBack(loop_, cb_, evt_, arg_);
 
  return true;
}

bool EpollDispatcher::removeEvt(Socket *sock_,
    EventType evt_)
{
  sock_->clearCallBack(evt_);
  epoll_event epEvt;
  if(epoll_ctl(epollFd, EPOLL_CTL_DEL, sock_->getFd(), &epEvt) != 0)
  {
    logTrace("epoll_ctl(EPOLL_CTL_DEL) failed,%m");
    return false;
  }

EventType evt = ~evt_&sock_->getEvt();
  if(0 == evt)
  {
    return true;
  }
 
  memset(&epEvt, 0, sizeof(epEvt));
  epEvt.data.fd = sock_->getFd();
 
  if(evt & evRead)
  {
    epEvt.events |= EPOLLIN;
  }
 
  if (evt & evWrite)
  {
    epEvt.events |= EPOLLOUT;
  }

if(epoll_ctl(epollFd, EPOLL_CTL_ADD, sock_->getFd(), &epEvt) != 0)
  {
    logTrace("epoll_ctl(EPOLL_CTL_ADD) failed,%m");
    return false;
  }

return true;
}

int EpollDispatcher::listen(SockMapT &sockMap_,
    int timeout)
{
  epoll_event epEvts[256];
  int num = epoll_wait(epollFd, epEvts, 256, timeout);

if(num <= 0)
  {
    logTrace("num=%d;size:%d;%m", num, sockMap_.size());
    return num;
  }

for(int idx = 0; idx < num; ++idx)
  {
    int fd = epEvts[idx].data.fd;
    SockMapT::iterator tmpIt = sockMap_.find(fd);
    if(tmpIt == sockMap_.end())
    {
      logTrace("can't find this fd in map");
      continue;
    }
 
    if(epEvts[idx].events & EPOLLIN)
    {
      tmpIt->second->processEvent(evRead);
    }
   
    if(epEvts[idx].events & EPOLLOUT)
    {
      tmpIt->second->processEvent(evWrite);
    }
  }
 
  return num;
}

基本就是对select、poll、epoll事件监听方式的封装。

注册事件时,要提供相应的callback函数,所谓callback就是提供一个函数指针,等相应的事件触发时,就调用相应的函数进行执行,MFC中到处都是这种callback。

转:sock_ev——linux平台socket事件框架(event dispatcher) .的更多相关文章

  1. 转:sock_ev——linux平台socket事件框架(event loop) .

    上一篇我们封装了三种事件监听方式,如果分别提供给客户端使用,有点不方便,也不利于统一管理:我们再封装一层EventLoop. /************************************ ...

  2. 转:sock_ev——linux平台socket事件框架(socket API的封装) .

    把linux平台提供的有关socket操作的API进行封装是有必要的:基于stream操作的流程与基于dgram操作的流程略有不同,分别放在两个类中,但两者又有很多相似的操作,因此写一个基类,让其继承 ...

  3. 转:sock_ev——linux平台socket事件框架(基于字节流的测试程序) .

    原文:http://blog.csdn.net/gdutliuyun827/article/details/8257186 由于工作与学习的需要,写了一个socket的事件处理框架,在公司写的已经使用 ...

  4. 转:sock_ev——linux平台socket事件框架(socket代理类) .

    前面分析了对socket基本操作的封装,并按照数据的传送方式写了两个类,本篇将写一个代理类提供给库的使用者使用的类. /**************************************** ...

  5. 转:sock_ev——linux平台socket事件框架(uri地址的解析) .

    在第一篇中,已经说明,传递的socket地址采取以下形式: [cpp] view plaincopyprint?stream://192.168.2.10:8080   dgram://192.168 ...

  6. 转:sock_ev——linux平台socket事件框架(基于数据报的测试程序) .

    上一篇已经做过注释,这一篇直接上代码 /******************************************************************************** ...

  7. 转:sock_ev——linux平台socket事件框架(logTrace) .

    写代码要有调试log,采用syslog的输出:一般会输出到"/var/log/messages" /**************************************** ...

  8. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  9. Linux平台用C++实现事件对象,同步线程

    前文在Win32平台上用C++实现了事件对象Event,对线程进行同步,以达到期望目的.这次在Linux平台上实现与之类似的事件对象.与其相关的一组API包括:pthread_mutex_init,p ...

随机推荐

  1. Codeforces Beta Round #8 B. Obsession with Robots 暴力

    B. Obsession with Robots 题目连接: http://www.codeforces.com/contest/8/problem/B Description The whole w ...

  2. 关于收到谷歌邮件 Googlebot can't access your site 的解决方法

    最近一段时间一直都收到谷歌的邮件,而且“新锐工作室”的关键字在谷歌收录及排名都没有了.下面图为谷歌蜘蛛无法抓取网站的截图,如果你在谷歌网管工具里收到类似消息,说明也中招了.[Webmaster Too ...

  3. Oracle密码忘记了解决办法

    Oracle密码忘记了怎么办?有时候我们可能忘记了一个用户的密码,但是又需要以这个用户做一些操作,又不能去修改掉这个用户的密码,这个时候,就可以利用一些小窍门,来完成操作.采用如下方法可以修改密码: ...

  4. LWIP轻量级TCPIP协议栈的移植

    http://blog.csdn.net/ygrx/article/details/8020516 好久没有做过技术工作了,前几天因为一些需要,要在ST的OS20平台上进行了LWIP的移植,有一些心得 ...

  5. innodb_buffer_pool_size=30G

    Starting program: /usr/local/mysql-5.6.27-linux-glibc2.5-x86_64/bin/mysqld-debug --user=mysql --data ...

  6. Cocos2d-x 水果忍者划痕效果

    网上找的一个关于水果忍者划痕的,效果还算凑合.其原理就是基于OpenGL绘制直线,因为版本号过老,此处笔者改动了一些方法,粘贴后可直接使用 适用于Cocos2d-x 2.2.1 .h文件里须要添�的代 ...

  7. golang的缓冲channel和无缓冲channel的区别

    话说golang的channel同步的定义真是让人无力吐槽,码农的用户体验就这么难搞么,超耐磨阿,无缓冲和缓冲居然有这么大区别....靠 转载一段网上的资料 --------------------- ...

  8. 【转载】Redis Sentinel 高可用服务架构搭建

    作者:田园里的蟋蟀 出处:http://www.cnblogs.com/xishuai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接. 阅读 ...

  9. 卷积神经网络LeNet Convolutional Neural Networks (LeNet)

    Note This section assumes the reader has already read through Classifying MNIST digits using Logisti ...

  10. HTML:图片和视频标签的使用

    介绍:在html网页中,图片和视频是基本的元素,在网页中插入图片和视频有自己的标签,分别是img.embed,来源都是使用src来链接. 插入图片: <img src="图片的来源&q ...