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.\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)