Linux非阻塞IO(七)使用epoll重新实现客户端
2014-10-27 20:37
603 查看
使用poll与epoll的区别主要在于:
理解了这部分代码,整理部分与poll基本一致:
poll可以每次重新装填fd数组,但是epoll的fd是一开始就加入了,不可能每次都重新加入
于是采用这种策略: epoll除了listenfd一开始就监听read事件,其他的客户fd加入epoll时,监听的事件都为空。
然后在每次epoll_wait之前,使用epoll_ctl重新设置fd的监听事件。
所以这部分的代码如下:然后在每次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重新实现客户端
- Linux非阻塞IO(八)使用epoll重新实现非阻塞的回射服务器
- Linux非阻塞IO(八)使用epoll重新实现非阻塞的回射服务器
- Linux非阻塞IO(五)使用poll实现非阻塞的回射服务器客户端
- Linux非阻塞IO(五)使用poll实现非阻塞的回射服务器客户端
- [Linux]实例浅析epoll的水平触发和边缘触发,以及边缘触发为什么要使用非阻塞IO
- Linux非阻塞IO(六)使用poll实现非阻塞的服务器端
- Linux非阻塞IO(六)使用poll实现非阻塞的服务器端
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO
- 使用epoll实现客户端UDP并发
- Python中使用select模块实现非阻塞的IO
- Linux非阻塞IO(三)非阻塞IO中缓冲区Buffer的实现
- linux AIO libaio和epoll实现非阻塞模型
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO
- 使用c语言实现在linux下的openssl客户端和服务器端编程
- Linux驱动学习8(非阻塞IO的实现--select/poll方法)
- Linux 下使用epoll实现转发服务器的小DEMO
- 【转】linux中使用命名管道实现客户端/服务器模型的进程间通信
- Linux下基于EPOLL 模型,实现用户登录,客户端采用QT
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO