Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1662852
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: 网络与安全

2014-02-24 18:01:15

http://blog.csdn.net/zhx6044/article/details/9320637

epoll相对于poll和select这两个多路复用的I/O模型更加的高效。epoll的函数很简单,麻烦的地方在于水平出发和边沿触发。

               用张图来说明下

              

ET(边沿)只是在状态反转时触发,比如从不可读到可读。而LT(水平)就是如果可读,就会一直触发。所以在使用ET的时候要做一些额外的处理,比如可读的,一直把缓冲区读完,进入不可读状态,下次来数据才会触发。

下面贴出代码,只是一个简单的练习的例子


点击(此处)折叠或打开

  1. #ifndef SOCKETHEADS_H
  2. #define SOCKETHEADS_H


  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <netinet/in.h>
  11. #include <fcntl.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>

  14. #endif //SOCKETHEADS_H


  15. #ifndef EPOLL_H
  16. #define EPOLL_H

  17. #include <sys/epoll.h>
  18. #include <unistd.h>


  19. /**
  20.  * @brief The Epoll class 对epoll的封装
  21.  */
  22. class Epoll
  23. {
  24. public:
  25.     /**
  26.      *
  27.      */
  28.     enum EPOLL_OP {ADD = EPOLL_CTL_ADD, MOD = EPOLL_CTL_MOD, DEL = EPOLL_CTL_DEL};
  29.     /**
  30.      * 最大的连接数和最大的回传事件数
  31.      */
  32.     Epoll(int _max = 30, int maxevents = 20);
  33.     ~Epoll();
  34.     int create();
  35.     int add(int fd, epoll_event *event);
  36.     int mod(int fd, epoll_event *event);
  37.     int del(int fd, epoll_event *event);
  38.     void setTimeout(int timeout);
  39.     void setMaxEvents(int maxevents);
  40.     int wait();
  41.     const epoll_event* events() const;
  42.     const epoll_event& operator[](int index)
  43.     {
  44.         return backEvents[index];
  45.     }
  46. private:
  47.     bool isValid() const;
  48.     int max;
  49.     int epoll_fd;
  50.     int epoll_timeout;
  51.     int epoll_maxevents;
  52.     epoll_event *backEvents;
  53. };




  54. #endif //EPOLL_H

  55. #include "zepoll.h"


  56. Epoll::Epoll(int _max, int maxevents):max(_max),
  57.     epoll_fd(-1),
  58.     epoll_timeout(0),
  59.     epoll_maxevents(maxevents),
  60.     backEvents(0)
  61. {

  62. }

  63. Epoll::~Epoll()
  64. {
  65.     if (isValid()) {
  66.         close(epoll_fd);
  67.     }
  68.     delete[] backEvents;
  69. }


  70. inline
  71. bool Epoll::isValid() const
  72. {
  73.     return epoll_fd > 0;
  74. }

  75. inline
  76. void Epoll::setTimeout(int timeout)
  77. {
  78.     epoll_timeout = timeout;
  79. }

  80. inline
  81. void Epoll::setMaxEvents(int maxevents)
  82. {
  83.     epoll_maxevents = maxevents;
  84. }

  85. inline
  86. const epoll_event* Epoll::events() const
  87. {
  88.     return backEvents;
  89. }



  90. int Epoll::create()
  91. {
  92.     epoll_fd = ::epoll_create(max);
  93.     if (isValid()) {
  94.         backEvents = new epoll_event[epoll_maxevents];
  95.     }
  96.     return epoll_fd;
  97. }

  98. int Epoll::add(int fd, epoll_event *event)
  99. {
  100.     if (isValid()) {
  101.         return ::epoll_ctl(epoll_fd, ADD, fd, event);
  102.     }
  103.     return -1;

  104. }

  105. int Epoll::mod(int fd, epoll_event *event)
  106. {
  107.     if (isValid()) {
  108.         return ::epoll_ctl(epoll_fd, MOD, fd, event);
  109.     }
  110.     return -1;

  111. }

  112. int Epoll::del(int fd, epoll_event *event)
  113. {
  114.     if (isValid()) {
  115.         return ::epoll_ctl(epoll_fd, DEL, fd, event);
  116.     }
  117.     return -1;
  118. }

  119. int Epoll::wait()
  120. {
  121.     if (isValid()) {
  122.         return ::epoll_wait(epoll_fd, backEvents, epoll_maxevents, epoll_timeout);
  123.     }
  124.     return -1;
  125. }

  126. /********************************************************************
  127. * author 周翔
  128. * e-mail 604487178@qq.com
  129. * blog http://blog.csdn.net/zhx6044
  130. **********************************************************************/

  131. #ifndef TASK_H
  132. #define TASK_H

  133. #include <string>
  134. #include <socketheads.h>

  135. /**
  136.  * @brief The Task class 任务类
  137.  */
  138. class Task
  139. {
  140. public:
  141.     typedef enum {CONNECT = 0, DISCONNECT, TALKING} TASKFLAG;
  142.     Task(const std::string &message, TASKFLAG flag = TALKING);
  143.     const std::string& getMessage() const;
  144.     TASKFLAG getFlag() const;
  145.     void setIP(in_addr _ip);
  146.     int getS_fd() const;

  147.     void setS_fd(int _fd);


  148.     std::string getData() const;


  149. private:
  150.     std::string m_message;
  151.     TASKFLAG m_flag;
  152.     in_addr ip;
  153.     int s_fd;
  154. };

  155. #endif // TASK_H

  156. /********************************************************************
  157. * author 周翔
  158. * e-mail 604487178@qq.com
  159. * blog http://blog.csdn.net/zhx6044
  160. **********************************************************************/

  161. #include "task.h"

  162. Task::Task(const std::string &message, TASKFLAG flag):
  163.     m_message(message),
  164.     m_flag(flag)
  165. {
  166. }


  167. const std::string& Task::getMessage() const
  168. {
  169.     return m_message;
  170. }

  171. Task::TASKFLAG Task::getFlag() const
  172. {
  173.     return m_flag;
  174. }

  175. void Task::setIP(in_addr _ip)
  176. {
  177.     ip = _ip;
  178. }

  179. int Task::getS_fd() const
  180. {
  181.     return s_fd;
  182. }

  183. void Task::setS_fd(int _fd)
  184. {
  185.     s_fd = _fd;
  186. }

  187. std::string Task::getData() const
  188. {
  189.     std::string re;
  190.     if (m_flag == CONNECT) {
  191.         re = ::inet_ntoa(ip) + std::string("----->") + "CONNECT! " + m_message;
  192.     } else {
  193.         if (m_flag == DISCONNECT) {
  194.             re = ::inet_ntoa(ip) + std::string("----->") + "DISCONNECT " + m_message;;
  195.         } else {
  196.             re = ::inet_ntoa(ip) + std::string("----->Talk:") + m_message;
  197.         }
  198.     }
  199.     return re;
  200. }

  201. #ifndef EPOLL_SERVER_H
  202. #define EPOLL_SERVER_H

  203. #include <map>
  204. #include <list>

  205. #include "zepoll.h"
  206. #include "socketheads.h"
  207. #include "task.h"


  208. typedef std::pair<int, in_addr> FDtoIP;

  209. /**
  210.  * @brief The Epoll_server class 服务器
  211.  */
  212. class Epoll_server
  213. {
  214. public:
  215.     Epoll_server(int port);
  216.     ~Epoll_server();
  217.     int bind();
  218.     int listen();
  219.     void poweroff();
  220.     bool states() const;
  221. private:
  222.     enum {BLOCKLOG = 5};

  223.     bool isValid() const;

  224.     int acceptSocketEpoll();
  225.     int readSocketEpoll(const epoll_event &ev);
  226.     int writeSocketEpoll(const epoll_event &ev);

  227.     void doTask(const Task &t);

  228.     int _port;
  229.     int server_socket_fd;
  230.     Epoll *_epoll;
  231.     sockaddr_in server_addr;
  232.     sockaddr_in client_addr;
  233.     epoll_event m_event;
  234.     bool on;


  235.     static int setNonblocking(int socket_fd);


  236.     std::list<FDtoIP> fd_IP;




  237. };

  238. #endif //EPOLL_SERVER_H

  239. #include "epoll_server.h"

  240. #include <iostream>


  241. //static char welcom[] = "welcom to my epoll_server";
  242. //static char sorry[] = "Sorry! This is a simple demo,so not any function!";
  243. //static char buf[BUFSIZ];


  244. Epoll_server::Epoll_server(int port):_port(port),
  245.     server_socket_fd(-1),
  246.     _epoll(0),
  247.     on(true)
  248. {


  249. }


  250. Epoll_server::~Epoll_server()
  251. {
  252.     if (isValid()) {
  253.         ::close(server_socket_fd);
  254.     }
  255.     delete _epoll;

  256. }


  257. inline
  258. bool Epoll_server::isValid() const
  259. {
  260.     return server_socket_fd > 0;
  261. }


  262. inline
  263. void Epoll_server::poweroff()
  264. {
  265.     on = false;
  266. }



  267. inline
  268. bool Epoll_server::states() const
  269. {
  270.     return on;
  271. }



  272. int Epoll_server::setNonblocking(int socket_fd)
  273. {
  274.     int opts;
  275.     opts = fcntl(socket_fd, F_GETFL);
  276.     if (opts < 0) {
  277.         return -1;
  278.     } else
  279.     {
  280.         opts = opts | O_NONBLOCK;
  281.         if (fcntl(socket_fd, F_SETFL, opts) < 0) {

  282.             return -1;
  283.         }
  284.     }
  285.     return 0;
  286. }


  287. void Epoll_server::doTask(const Task &t)
  288. {
  289.     std::list<FDtoIP>::iterator ite = fd_IP.begin();
  290.     std::list<FDtoIP>::iterator ite1 = fd_IP.end();
  291.     for (;ite != fd_IP.end();++ite) {
  292.         if ((*ite).first != t.getS_fd()) {
  293.             memset(&m_event, '\0', sizeof(m_event));
  294.             m_event.events = EPOLLOUT | EPOLLET;
  295.             Task *c = new Task(t);
  296.             c->setS_fd((*ite).first);
  297.             m_event.data.ptr = static_cast<void*>(c);
  298.             _epoll->mod((*ite).first, &m_event);
  299.         } else {
  300.             ite1 = ite;
  301.         }
  302.     }
  303.     if (t.getFlag() == Task::DISCONNECT) {
  304.         if (ite1 != fd_IP.end()) {
  305.             fd_IP.erase(ite1);
  306.         }

  307.     }

  308. }
  309. /**
  310.  * @brief Epoll_server::acceptSocketEpoll 有用户接入
  311.  * @return
  312.  */
  313. int Epoll_server::acceptSocketEpoll()
  314. {
  315.     socklen_t len = sizeof(struct sockaddr_in);
  316.     int connect_fd;
  317.     while ((connect_fd = ::accept(server_socket_fd,
  318.                                   (struct sockaddr*)(&client_addr), &len)) > 0) {
  319.         if (setNonblocking(connect_fd) < 0) {
  320.             ::close(connect_fd);
  321.             continue;
  322.         }
  323.         m_event.data.fd = connect_fd;
  324.         m_event.events = EPOLLIN | EPOLLET;
  325.         if (_epoll->add(connect_fd, &m_event) < 0) {
  326.             ::close(connect_fd);
  327.             continue;
  328.         } else {

  329.             fd_IP.push_back(FDtoIP(connect_fd, client_addr.sin_addr));
  330.             Task t("come in", Task::CONNECT);
  331.             t.setIP(client_addr.sin_addr);
  332.             t.setS_fd(connect_fd);
  333.             doTask(t);

  334.         }



  335.     }

  336.     if (connect_fd == -1 && errno != EAGAIN && errno != ECONNABORTED
  337.             && errno != EPROTO && errno !=EINTR) {
  338.         return -1;

  339.     }



  340.     return 0;


  341. }


  342. int Epoll_server::readSocketEpoll(const epoll_event &ev)
  343. {
  344.     int n = 0;
  345.     int nread = 0;
  346.     char buf[BUFSIZ]={'\0'};
  347.     while ((nread = ::read(ev.data.fd, buf + n, BUFSIZ-1)) > 0) {
  348.         n += nread;
  349.     }
  350.     if (nread == -1 && errno != EAGAIN) {
  351.         return -1;
  352.     }

  353.     std::list<FDtoIP>::iterator ite = fd_IP.begin();
  354.     for (;ite != fd_IP.end();++ite) {
  355.         if ((*ite).first == ev.data.fd) {
  356.             break;
  357.         }
  358.     }

  359.     if (nread == 0) {
  360.         strcpy(buf, " disconet left ");
  361.         Task t(buf,Task::DISCONNECT);
  362.         t.setIP(client_addr.sin_addr);
  363.         t.setS_fd((*ite).first);
  364.         doTask(t);
  365.     } else {
  366.         Task t(buf,Task::TALKING);
  367.         t.setIP(client_addr.sin_addr);
  368.         t.setS_fd((*ite).first);
  369.         doTask(t);
  370.     }

  371.     // Task *t = new Task(buf,Task::DISCONNECT);
  372.     // t->setIP((*ite).second);
  373.     // t->setS_fd((*ite).first);




  374.     // m_event.data.fd = ev.data.fd;
  375.     // m_event.events = ev.events;
  376.     return 0;//_epoll->mod(m_event.data.fd, &m_event);
  377. }


  378. int Epoll_server::writeSocketEpoll(const epoll_event &ev)
  379. {
  380.     Task *t = static_cast<Task*>(ev.data.ptr);
  381.     const char* buf = t->getData().data();
  382.     int nwrite = 0, data_size = strlen(buf);
  383.     int fd = t->getS_fd();
  384.     int n = data_size;
  385.     delete t;
  386.     while (n > 0) {
  387.         nwrite = ::write(fd, buf + data_size - n, n);
  388.         if (nwrite < 0) {
  389.             if (nwrite == -1 && errno != EAGAIN) {
  390.                 return -1;
  391.             }
  392.             break;
  393.         }
  394.         n -= nwrite;
  395.     }

  396.     memset(&m_event, '\0', sizeof(m_event));
  397.     // m_event.events &= ~EPOLLOUT;
  398.     m_event.events = EPOLLIN | EPOLLET;
  399.     m_event.data.fd = fd;
  400.     if (_epoll->mod(fd, &m_event) < 0) {
  401.         ::close(m_event.data.fd);
  402.         return -1;
  403.     }
  404.     return 0;
  405. }

  406. /**
  407.  * @brief Epoll_server::bind
  408.  * @return
  409.  */
  410. int Epoll_server::bind()
  411. {
  412.     server_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  413.     if (server_socket_fd < 0) {
  414.         return -1;
  415.     }

  416.     setNonblocking(server_socket_fd);

  417.     _epoll = new Epoll();
  418.     if (_epoll->create() < 0) {
  419.         return -1;
  420.     }
  421.     memset(&m_event, '\0', sizeof(m_event));
  422.     m_event.data.fd = server_socket_fd;
  423.     m_event.events = EPOLLIN | EPOLLET;
  424.     _epoll->add(server_socket_fd, &m_event);

  425.     memset(&server_addr, 0 ,sizeof(server_addr));
  426.     server_addr.sin_family = AF_INET;
  427.     server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  428.     server_addr.sin_port = htons(_port);

  429.     return ::bind(server_socket_fd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr));

  430. }


  431. int Epoll_server::listen()
  432. {
  433.     if (isValid()) {
  434.         if (::listen(server_socket_fd, BLOCKLOG) < 0) {
  435.             return -1;
  436.         } else {
  437.             int num;
  438.             while (on) {
  439.                 num = _epoll->wait();
  440.                 for (int i = 0;i < num;++i) {
  441.                     /**
  442.                      * 接受连接的连接,把她加入到epoll中
  443.                      */
  444.                     if ((*_epoll)[i].data.fd == server_socket_fd) {
  445.                         if (acceptSocketEpoll() < 0) {
  446.                             break;
  447.                         }
  448.                         continue;

  449.                     }
  450.                     /**
  451.                      * EPOLLIN event
  452.                      */
  453.                     if ((*_epoll)[i].events & EPOLLIN) {
  454.                         if (readSocketEpoll((*_epoll)[i]) < 0) {
  455.                             break;
  456.                         }
  457.                         continue;


  458.                     }

  459.                     /**
  460.                      * EPOLLOUT event
  461.                      */
  462.                     if ((*_epoll)[i].events & EPOLLOUT) {
  463.                         if (writeSocketEpoll((*_epoll)[i]) < 0) {
  464.                             break;
  465.                         }

  466.                     }
  467.                 }
  468.             }
  469.         }
  470.     }
  471.     return -1;
  472. }


  473. #include "epoll_server.h"

  474. #include <iostream>



  475. int main(int /*argc*/, char const **/*argv[]*/)
  476. {
  477.     std::cout << "server" << std::endl;
  478.     Epoll_server s(18090);
  479.     if (s.bind() < 0) {
  480.         return -1;
  481.     }
  482.     return s.listen();
  483. }

需要客户端程序的在这里


阅读(1087) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~