zoukankan      html  css  js  c++  java
  • Linux非阻塞IO(七)使用epoll重新实现客户端

    使用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.
    ");
                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.
    ");
                            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.
    ");
                            exit(EXIT_SUCCESS);
                        } 
                    }
    
                    if(peerfd == STDOUT_FILENO && revents & kWriteREvent)
                    {
                        buffer_write(&recvbuf, peerfd); //将recvbuf中的数据输出至stdout
                    }
                }
            }
    
        }
    
    }
  • 相关阅读:
    【XR-4】文本编辑器
    二十四、JMeter实战-Linux下搭建JMeter + Ant + Jenkins自动化框架
    Python 接口自动化
    Docker 部署 Tomcat
    CentOS7 查看 ip 地址
    Python
    Python接口自动化 -RESTful请求方法封装
    Python接口自动化
    Python
    xcode 编译webdriveragent
  • 原文地址:https://www.cnblogs.com/inevermore/p/4055057.html
Copyright © 2011-2022 走看看