使用poll与epoll的区别主要在于:

poll可以每次重新装填fd数组,但是epoll的fd是一开始就加入了,不可能每次都重新加入

于是采用这种策略:

epoll除了listenfd一开始就监听read事件,其他的客户fd加入epoll时,监听的事件都为空。

然后在每次epoll_wait之前,使用epoll_ctl重新设置fd的监听事件。

所以这部分的代码如下:

 

  1. //重新装填epoll事件
  2. sockfd_event = 0;
  3. stdin_event = 0;
  4. stdout_event = 0;
  5. //epoll无法每次都重新装填,所以给每个fd添加一个空事件
  6.  
  7. if(buffer_is_readable(&sendbuf))
  8. {
  9. sockfd_event |= kWriteEvent;
  10. }
  11. if(buffer_is_writeable(&sendbuf))
  12. {
  13. stdin_event |= kReadEvent;
  14. }
  15. if(buffer_is_readable(&recvbuf))
  16. {
  17. stdout_event |= kWriteEvent;
  18. }
  19. if(buffer_is_writeable(&recvbuf))
  20. {
  21. sockfd_event |= kReadEvent;
  22. }
  23.  
  24. epoll_mod_fd(epollfd, sockfd, sockfd_event);
  25. epoll_mod_fd(epollfd, STDIN_FILENO, stdin_event);
  26. epoll_mod_fd(epollfd, STDOUT_FILENO, stdout_event);

理解了这部分代码,整理部分与poll基本一致:

  1. #define _GNU_SOURCE
  2. #include "sysutil.h"
  3. #include "buffer.h"
  4. #include <sys/epoll.h>
  5.  
  6. int main(int argc, char const *argv[])
  7. {
  8. //创建client套接字
  9. int sockfd = tcp_client(0);
  10. //调用非阻塞connect函数
  11. int ret = nonblocking_connect(sockfd, "localhost", 9981, 5000);
  12. if(ret == -1)
  13. {
  14. perror("Connect Timeout .");
  15. exit(EXIT_FAILURE);
  16. }
  17.  
  18. //将三个fd设置为Non-Blocking
  19. activate_nonblock(sockfd);
  20. activate_nonblock(STDIN_FILENO);
  21. activate_nonblock(STDOUT_FILENO);
  22.  
  23. buffer_t recvbuf; //sockfd -> Buffer -> stdout
  24. buffer_t sendbuf; //stdin -> Buffer -> sockfd
  25.  
  26. //初始化缓冲区
  27. buffer_init(&recvbuf);
  28. buffer_init(&sendbuf);
  29.  
  30. //创建epoll
  31. int epollfd = epoll_create1(0);
  32. if(epollfd == -1)
  33. ERR_EXIT("create epoll");
  34. struct epoll_event events[1024];
  35.  
  36. uint32_t sockfd_event = 0;
  37. uint32_t stdin_event = 0;
  38. uint32_t stdout_event = 0;
  39.  
  40. epoll_add_fd(epollfd, sockfd, sockfd_event);
  41. epoll_add_fd(epollfd, STDIN_FILENO, stdin_event);
  42. epoll_add_fd(epollfd, STDOUT_FILENO, stdout_event);
  43.  
  44. while(1)
  45. {
  46. //重新装填epoll事件
  47. sockfd_event = 0;
  48. stdin_event = 0;
  49. stdout_event = 0;
  50. //epoll无法每次都重新装填,所以给每个fd添加一个空事件
  51.  
  52. if(buffer_is_readable(&sendbuf))
  53. {
  54. sockfd_event |= kWriteEvent;
  55. }
  56. if(buffer_is_writeable(&sendbuf))
  57. {
  58. stdin_event |= kReadEvent;
  59. }
  60. if(buffer_is_readable(&recvbuf))
  61. {
  62. stdout_event |= kWriteEvent;
  63. }
  64. if(buffer_is_writeable(&recvbuf))
  65. {
  66. sockfd_event |= kReadEvent;
  67. }
  68.  
  69. epoll_mod_fd(epollfd, sockfd, sockfd_event);
  70. epoll_mod_fd(epollfd, STDIN_FILENO, stdin_event);
  71. epoll_mod_fd(epollfd, STDOUT_FILENO, stdout_event);
  72.  
  73. //监听fd数组
  74. int nready = epoll_wait(epollfd, events, 1024, 5000);
  75. if(nready == -1)
  76. ERR_EXIT("epoll wait");
  77. else if(nready == 0)
  78. {
  79. printf("epoll timeout.\n");
  80. continue;
  81. }
  82. else
  83. {
  84. int i;
  85. for(i = 0; i < nready; ++i)
  86. {
  87. int peerfd = events[i].data.fd;
  88. int revents = events[i].events;
  89. if(peerfd == sockfd && revents & kReadREvent)
  90. {
  91. //从sockfd接收数据到recvbuf
  92. if(buffer_read(&recvbuf, peerfd) == 0)
  93. {
  94. fprintf(stderr, "server close.\n");
  95. exit(EXIT_SUCCESS);
  96. }
  97. }
  98.  
  99. if(peerfd == sockfd && revents & kWriteREvent)
  100. {
  101. buffer_write(&sendbuf, peerfd); //将sendbuf中的数据写入sockfd
  102. }
  103.  
  104. if(peerfd == STDIN_FILENO && revents & kReadREvent)
  105. {
  106. //从stdin接收数据写入sendbuf
  107. if(buffer_read(&sendbuf, peerfd) == 0)
  108. {
  109. fprintf(stderr, "exit.\n");
  110. exit(EXIT_SUCCESS);
  111. }
  112. }
  113.  
  114. if(peerfd == STDOUT_FILENO && revents & kWriteREvent)
  115. {
  116. buffer_write(&recvbuf, peerfd); //将recvbuf中的数据输出至stdout
  117. }
  118. }
  119. }
  120.  
  121. }
  122.  
  123. }

Linux非阻塞IO(七)使用epoll重新实现客户端的更多相关文章

  1. Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合

    上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型.   阻塞IO   过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ...

  2. Linux非阻塞IO(六)使用poll实现非阻塞的服务器端

    关于poll模型监听的事件以及返回事件,我们定义宏如下: #define kReadEvent (POLLIN | POLLPRI) #define kWriteEvent (POLLOUT | PO ...

  3. Linux非阻塞IO(五)使用poll实现非阻塞的回射服务器客户端

    前面几节我们讨论了非阻塞IO的基本概念.Buffer的设计以及非阻塞connect的实现,现在我们使用它们来完成客户端的编写. 我们在http://www.cnblogs.com/inevermore ...

  4. Linux非阻塞IO(四)非阻塞IO中connect的实现

    我们为客户端的编写再做一些工作. 这次我们使用非阻塞IO实现connect函数. int connect(int sockfd, const struct sockaddr *addr, sockle ...

  5. Linux非阻塞IO(三)非阻塞IO中缓冲区Buffer的实现

    本文我们来实现回射服务器的Buffer.   Buffer的实现   上节提到了非阻塞IO必须具备Buffer.再次将Buffer的设计描述一下: 这里必须补充一点,writeIndex指向空闲空间的 ...

  6. Linux非阻塞IO(八)使用epoll重新实现非阻塞的回射服务器

    本文无太多内容,主要是几个前面提到过的注意点: 一是epoll的fd需要重新装填.我们将tcp_connection_t的指针保存在数组中,所以我们以这个数组为依据,重新装填fd的监听事件. //重新 ...

  7. linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

      IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...

  8. 实例浅析epoll的水平触发和边缘触发,以及边缘触发为什么要使用非阻塞IO

    一.基本概念                                                          我们通俗一点讲: Level_triggered(水平触发):当被监控的 ...

  9. 转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】

    下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架, ...

随机推荐

  1. LINK : fatal error LNK1104: 无法打开文件“mfc71.lib”(转)

    原文转自 http://blog.csdn.net/mxclxp/article/details/8196142 [环境]  Windows XP OS:  Visual Studio 2008:  ...

  2. IE浏览器对虚拟主机配置域名的问题

    之前一直搞不明白web开发做本地调试的时候IE浏览器老是无法登陆,而谷歌和其他内核浏览器能正常登陆的问题,后来发现IE浏览器对WEB服务器配置的虚拟主机域名规则是不能包含这个'_'下划线符号的,否则会 ...

  3. PHP获取IP的方法

    function getIP() { if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $realip = $_SERVER['HTTP_X_FORWARD ...

  4. 使用Android Studio开发调用.NET Webservice 之初体验

    本人是.NET出身 但苦于领导要让研究Android 外壳然后准备套html5  ,当试验兵真坑啊 但也没办法 咱还得研究啊,索性 不辜负领导的期望(也研究好两三天了)总算弄明白了 app本地存储 和 ...

  5. css伪类元素:after 的多功能用法——任意大小的底边框

    需求用法出现的背景: 由于项目UI的优化,项目中所有tab导航选中的状态都是统一样式书写的,之前都是用的border-bottom,新的需求如果用以前的本办法就是定位一个选中边框在底部,但是涉及的模板 ...

  6. ASP.NET Code First Update-Database

    问题描述: 复制了一个模块化的MVC5的项目,模块化的解释是说不同功能的模块分开来放的. 明确每个模块都是做什么工作的. 首先最基本的,就是根据Apps.Models模块来创建数据库了. 做法是卸载A ...

  7. IE常见兼容问题

    图片有边框 CSS 增加 border:0; border,在IE 模式下不算在宽度内;

  8. 51nod 1137.矩阵乘法-矩阵乘法

    1137 矩阵乘法 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题   给出2个N * N的矩阵M1和M2,输出2个矩阵相乘后的结果.   Input 第1行:1个数N, ...

  9. Codeforces 938D Buy a Ticket (转化建图 + 最短路)

    题目链接  Buy a Ticket 题意   给定一个无向图.对于每个$i$ $\in$ $[1, n]$, 求$min\left\{2d(i,j) + a_{j}\right\}$ 建立超级源点$ ...

  10. Python与数据库[1] -> 数据库接口/DB-API[2] -> SQL Server 适配器

    SQL_Server适配器 / SQL_Server Adapter 1 环境配置 / Environment Configuration 安装SQL_Server的Python适配器包 pip in ...