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

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

于是采用这种策略:

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

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

所以这部分的代码如下:

 

//重新装填epoll事件
sockfd_event = 0;
stdin_event = 0;
stdout_event = 0;
//epoll无法每次都重新装填,所以给每个fd添加一个空事件 if(buffer_is_readable(&sendbuf))
{
sockfd_event |= kWriteEvent;
}
if(buffer_is_writeable(&sendbuf))
{
stdin_event |= kReadEvent;
}
if(buffer_is_readable(&recvbuf))
{
stdout_event |= kWriteEvent;
}
if(buffer_is_writeable(&recvbuf))
{
sockfd_event |= kReadEvent;
} epoll_mod_fd(epollfd, sockfd, sockfd_event);
epoll_mod_fd(epollfd, STDIN_FILENO, stdin_event);
epoll_mod_fd(epollfd, STDOUT_FILENO, stdout_event);

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

#define _GNU_SOURCE
#include "sysutil.h"
#include "buffer.h"
#include <sys/epoll.h> int main(int argc, char const *argv[])
{
//创建client套接字
int sockfd = tcp_client(0);
//调用非阻塞connect函数
int ret = nonblocking_connect(sockfd, "localhost", 9981, 5000);
if(ret == -1)
{
perror("Connect Timeout .");
exit(EXIT_FAILURE);
} //将三个fd设置为Non-Blocking
activate_nonblock(sockfd);
activate_nonblock(STDIN_FILENO);
activate_nonblock(STDOUT_FILENO); buffer_t recvbuf; //sockfd -> Buffer -> stdout
buffer_t sendbuf; //stdin -> Buffer -> sockfd //初始化缓冲区
buffer_init(&recvbuf);
buffer_init(&sendbuf); //创建epoll
int epollfd = epoll_create1(0);
if(epollfd == -1)
ERR_EXIT("create epoll");
struct epoll_event events[1024]; uint32_t sockfd_event = 0;
uint32_t stdin_event = 0;
uint32_t stdout_event = 0; epoll_add_fd(epollfd, sockfd, sockfd_event);
epoll_add_fd(epollfd, STDIN_FILENO, stdin_event);
epoll_add_fd(epollfd, STDOUT_FILENO, stdout_event); while(1)
{
//重新装填epoll事件
sockfd_event = 0;
stdin_event = 0;
stdout_event = 0;
//epoll无法每次都重新装填,所以给每个fd添加一个空事件 if(buffer_is_readable(&sendbuf))
{
sockfd_event |= kWriteEvent;
}
if(buffer_is_writeable(&sendbuf))
{
stdin_event |= kReadEvent;
}
if(buffer_is_readable(&recvbuf))
{
stdout_event |= kWriteEvent;
}
if(buffer_is_writeable(&recvbuf))
{
sockfd_event |= kReadEvent;
} epoll_mod_fd(epollfd, sockfd, sockfd_event);
epoll_mod_fd(epollfd, STDIN_FILENO, stdin_event);
epoll_mod_fd(epollfd, STDOUT_FILENO, stdout_event); //监听fd数组
int nready = epoll_wait(epollfd, events, 1024, 5000);
if(nready == -1)
ERR_EXIT("epoll wait");
else if(nready == 0)
{
printf("epoll timeout.\n");
continue;
}
else
{
int i;
for(i = 0; i < nready; ++i)
{
int peerfd = events[i].data.fd;
int revents = events[i].events;
if(peerfd == sockfd && revents & kReadREvent)
{
//从sockfd接收数据到recvbuf
if(buffer_read(&recvbuf, peerfd) == 0)
{
fprintf(stderr, "server close.\n");
exit(EXIT_SUCCESS);
}
} if(peerfd == sockfd && revents & kWriteREvent)
{
buffer_write(&sendbuf, peerfd); //将sendbuf中的数据写入sockfd
} if(peerfd == STDIN_FILENO && revents & kReadREvent)
{
//从stdin接收数据写入sendbuf
if(buffer_read(&sendbuf, peerfd) == 0)
{
fprintf(stderr, "exit.\n");
exit(EXIT_SUCCESS);
}
} if(peerfd == STDOUT_FILENO && revents & kWriteREvent)
{
buffer_write(&recvbuf, peerfd); //将recvbuf中的数据输出至stdout
}
}
} } }

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. CodeForces 659D Bicycle Race (判断点是否为危险点)

    D - Bicycle Race Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u S ...

  2. 【IDEA】IDEA集成Tomcat7插件运行项目

    Maven已经是Java的项目管理标配,如何在JavaEE开发使用Maven调用Web应用,是很多同学关心的问题.本文将介绍,Maven如何介绍Tomcat插件. Maven Tomcat插件现在主要 ...

  3. functools模块方法学习(1):partial

    函数的partial应用 典型的,函数在执行时,要带上所有必要的参数进行调用.然后,有时参数可以在函数被调用之前提前获知.这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调 ...

  4. Centos查看文件夹大小

    查看当前目录下文件夹大小 du -h --max-depth=1 查看整体情况 df -h

  5. Visual Studio跨平台开发(3):Xamarin iOS多页面应用开发

    前言 在前一篇教学中, 我们学会如何使用Visual Studio 搭配Xcode进行iOS基本控制项的操作. 但都是属于单一画面的应用程式. 这次我们要来练习如何通过Navigation Contr ...

  6. 在16aspx.com上下了一个.net程序,怎么修改它的默认登录名和密码?

    正常应该有个login.aspx文件,找到登入按钮事件,查看验证用户名密码事件,这个验证就有去搜索用户表,然后在这个用户表修改用户名密码就行了.不排除其他表有用用户名关联

  7. 蓝桥杯模拟赛 引爆炸弹-并查集+DFS

    引爆炸弹 在一个 n×m的方格地图上,某些方格上放置着炸弹.手动引爆一个炸弹以后,炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去. 现在为了引爆地图上的所有炸弹, ...

  8. Python与数据库[2] -> 关系对象映射/ORM[1] -> sqlalchemy 的基本使用示例

    sqlalchemy 的基本使用示例 下面的例子中将利用sqlalchemy进行数据库的连接,通过orm方式利用类实例属性操作的方式对数据库进行相应操作,同时应用一些常用的函数. 完整代码如下: fr ...

  9. Java-静态代码块,构造代码块,构造函数

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次 构造代码块:类中直接用{}定义,每一次创建对象时执行. 执行顺序优先级:静态块, main(),函数,构造块,构造方法. 构造函数 pu ...

  10. [洛谷3796]【模板】AC自动机(加强版)

    题目大意: 给定$n(n\leq150)$个模式串$p_i(|p_i|\le70)$和一个$t(|t|\le10^6)$,求$t$中被匹配次数最多的$p_i$. 思路: AC自动机.匹配时记录一下匹配 ...