面向接口的網絡處理模型(封裝select, epoll, poll)

天上午很不幸碰到一個select的問題,幸好以前對網絡I/O處理的模塊進行了封裝,今天下午很快就完成了一個基於poll的I/O處理封裝,
 
只需要進行1行代碼的替換,就可以輕鬆從select架構轉換到poll,同理也可以轉換到epoll。
 
自己可以隨心所欲的切換網絡I/O處理架構!!!
 
這裏是接口,使用的是模板,這裏沒有使用C++的繼承,有如下幾點考慮:
 
(1) 效率, 模板實現的多態是發生在編譯的時候,而繼承重載虛函數是通過程序運行的時候,根據vtable指針對函數的實際地址進行尋址,
 
            當然比模板慢, 而且還可能會增加4字節的vptr指針
 
(2) 面向接口編程: 繼承一般是有實際的邏輯含義的對象的使用,比如人,黑人之間。
 
                而我們的網絡處理模型,只是不同的處理方法,所以用模板更好一些
 
 
 
 
下面的代碼請放到一個頭文件中,不然存在編譯問題,詳情請見<<C++templates>>第6章
 
這裏對fd的訪問採用的是迭代模式,必須先啓動開始迭代,讓後才能依次迭代。
 
具體的網絡模型對fd存放形式對於調用者是不可見的, 只能獲取迭代指針,訪問網絡模型的內部fd列表。
 
各個實現類內存的數據結構自己是可以優化的,目前是全部採用數組
 
template <class T>
class InterfaceIOQuery
{
 private:
 
  T member;
 
 public:
 
  //添加一個關心的fd
  void remove(int* pFd, int iOption);
 
  //測試該fd是否可讀
  bool isCanRead(int* pIterator);
   
  //測試該fd是否可寫
  bool isCanWrite(int* pIterator);
 
  //測試該fd是否異常
  bool isExcept(int* pIterator);
 
  //設置關心的事件
  void setQueryOption(int iOption); 
 
  //註冊一個fd
  void registerFd(int pFd, int iOption);
 
  //輪詢操作, -1 永久等待, 0輪詢,  >0, 按時間輪詢
  int selectWithTime(int iTime);
 
  //開始遍歷fd列表
  int* getSelectFdBegin();
 
    //取得下一個fd的指針
   int* getSelectFdNext();
 
};
 
 
 
 
具體的select和poll, 接口的實現請見附件,
 
使用的範例代碼如下:
//設置關心的事件
m_selector.setQueryOption(OP_READ);
//註冊fd和該fd關心的事件
m_selector.registerFd(m_workPipeFd[0], OP_READ);
 
 int iReady;
 
 for ( ; ; )
 {
  //進行select操作
  iReady = m_selector.selectWithTime(-1);
 
  if (iReady < 0)
  {
   throw CException(errno);
  }
  else if (iReady == 0)
  {
   m_log.writeLog(LOG_INFO, "doSelect()", "work%d do select with 1 second time out", m_iThreadID);
  }
  else
  {
    //開始迭代訪問
   m_selector.getSelectFdBegin();
 
   int* iterator;
   
    //爲NULL標識訪問完畢
   while (NULL != (iterator = m_selector.getSelectFdNext()))
     
   {
    if (m_selector.isCanRead(iterator))
    {
     if (*iterator == m_workPipeFd[0])
     {
      int iRecive;
      int iRead = r_read(*iterator, (void*)(&iRecive), sizeof(iRecive));
 
      if (iRead <= 0)
      {
       m_log.writeLog(LOG_ERR, "doSelect()", "work%d read pipe %d fail ", m_iThreadID, *iterator);
      }
      else
      {
       m_log.writeLog(LOG_INFO, "doSelect()", "work%d recevie fd %d success ", m_iThreadID, iRecive);
       m_selector.registerFd(iRecive, OP_READ);
      }
      
     }
     else
     {
      replayToClient(iterator);
     }
     
     --iReady;
 
     if (0 == iReady)
     {
      break;
     }
    }
   }
  }
 }
  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章