zoukankan      html  css  js  c++  java
  • 转:sock_ev——linux平台socket事件框架(event dispatcher) .

    最近比较忙,好久没更新了;今天我们看一下事件的监听方式,在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。

  • 相关阅读:
    python之函数嵌套与闭包
    python之高阶函数
    python之装饰器
    python之内置函数
    python之内置函数:map ,filter ,reduce总结
    Python之reduce函数
    install python2 python3 in same computer
    git basic
    git LF CRLF
    2 thread, first to open chat window, second to make the phone
  • 原文地址:https://www.cnblogs.com/skyofbitbit/p/3672915.html
Copyright © 2011-2022 走看看