40_EPOLL的封装和使用

不改变整体流程,把epoll封装为一个即插即用的接口类。和select类似

CELLEpoll.hpp

#ifndef _CELL_EPOLL_HPP_
#define _CELL_EPOLL_HPP_

#if __linux__
//----------
#include"CELL.hpp"
#include"CELLClient.hpp"
#include"CELLLog.hpp"
#include<sys/epoll.h>
#define EPOLL_ERROR            (-1)
//----------

class CELLEpoll
{
public:
    ~CELLEpoll()
    {
        destory();
    }

    int create(int nMaxEvents)
    {
        if(_epfd > 0)
        {
            //Warring
            destory();
        }
        //linux 2.6.8 后size就没有作用了
        //由epoll动态管理,理论最大值为filemax
        //通过cat /proc/sys/fs/file-max来查询
        //ulimit -n
        _epfd = epoll_create(nMaxEvents);
        if(EPOLL_ERROR == _epfd)
        {
            CELLLog_PError("epoll_create");
            return _epfd;
        }
        _pEvents = new epoll_event[nMaxEvents];
        _nMaxEvents = nMaxEvents;
        return _epfd;
    }

    void destory()
    {
        if(_epfd > 0)
        {
            CELLNetWork::destorySocket(_epfd);
            _epfd = -1;
        }

        if(_pEvents)
        {
            delete[] _pEvents;
            _pEvents = nullptr;
        }
    }

    //向epoll对象注册需要管理、监听的Socket文件描述符
    int ctl(int op, SOCKET sockfd, uint32_t events)
    {
        epoll_event ev;
        //事件类型
        ev.events = events;
        //事件关联的socket描述符对象
        ev.data.fd = sockfd;
        //向epoll对象注册需要管理、监听的Socket文件描述符
        //并且说明关心的事件
        //返回0代表操作成功,返回负值代表失败 -1
        int ret = epoll_ctl(_epfd, op, sockfd, &ev);
        if(EPOLL_ERROR == ret)
        {
            CELLLog_PError("epoll_ctl1");
        }
        return ret;
    }

        //向epoll对象注册需要管理、监听的Socket文件描述符
    int ctl(int op, CELLClient* pClient, uint32_t events)
    {
        epoll_event ev;
        //事件类型
        ev.events = events;
        //事件关联的socket描述符对象
        ev.data.ptr = pClient;
        //向epoll对象注册需要管理、监听的Socket文件描述符
        //并且说明关心的事件
        //返回0代表操作成功,返回负值代表失败 -1
        int ret = epoll_ctl(_epfd, op, pClient->sockfd(), &ev);
        if(EPOLL_ERROR == ret)
        {
            CELLLog_PError("epoll_ctl2");
        }
        return ret;
    }

    int wait(int timeout)
    {
        //epfd epoll对象的描述符
        //events 用于接收检测到的网络事件的数组
        //maxevents 接收数组的大小,能够接收的事件数量
        //timeout
        //      t=-1 直到有事件发生才返回
        //      t= 0 立即返回 std::map
        //      t> 0 如果没有事件那么等待t毫秒后返回。
        int ret = epoll_wait(_epfd, _pEvents, _nMaxEvents, timeout);
        if(EPOLL_ERROR == ret)
        {
            if(errno == EINTR)
            {
                CELLLog_Info("epoll_wait EINTR");
                return 0;
            }
            CELLLog_PError("epoll_wait");
        }
        return ret;
    }

    epoll_event* events()
    {
        return _pEvents;
    }
private:
    //用于接收检测到的网络事件的数组
    epoll_event* _pEvents = nullptr;
    //
    int _nMaxEvents = 1;
    //
    int _epfd = -1;
};

#endif //__linux__
#endif // !_CELL_EPOLL_HPP_

在和客户端进行信息交互的server端引入epoll

CELLEpollServer.hpp

#ifndef _CELLEpollServer_HPP_
#define _CELLEpollServer_HPP_

#include"CELLServer.hpp"
#include"CELLEpoll.hpp"

//网络消息接收处理服务类
class CELLEpollServer:public CELLServer
{
public:
    CELLEpollServer()
    {
        _ep.create(10240);
    }

    ~CELLEpollServer() noexcept
    {
        Close();
    }

    bool DoNetEvents()
    {
        for (auto iter : _clients)
        {   //需要写数据的客户端,才加入EPOLLOUT检测是否可写
            if (iter.second->needWrite())
            {
                _ep.ctl(EPOLL_CTL_MOD, iter.second, EPOLLIN|EPOLLOUT);
            }else{
                _ep.ctl(EPOLL_CTL_MOD, iter.second, EPOLLIN);
            }
        }
        //---
        int ret = _ep.wait(1);
        if (ret < 0)
        {
            CELLLog_Error("CELLEpollServer%d.OnRun.wait", _id);
            return false;
        }
        else if (ret == 0)
        {
            return true;
        }
        //---
        auto events = _ep.events();
        for(int i = 0; i < ret; i++)
        {
            CELLClient* pClient = (CELLClient*)events[i].data.ptr;
            //当服务端socket发生事件时,表示有新客户端连接
            if(pClient)
            {
                if(events[i].events & EPOLLIN)
                {
                    if (SOCKET_ERROR == RecvData(pClient))
                    {
                        rmClient(pClient);
                        continue;
                    }
                }
                if(events[i].events & EPOLLOUT)
                {
                    if (SOCKET_ERROR == pClient->SendDataReal())
                    {
                        rmClient(pClient);
                    }
                }
            }
        }
        return true;
    }

    void rmClient(CELLClient* pClient)
    {
        auto iter = _clients.find(pClient->sockfd());
        if(iter != _clients.end())
        _clients.erase(iter);
        //
        OnClientLeave(pClient);
    }

    void OnClientJoin(CELLClient* pClient)
    {
        _ep.ctl(EPOLL_CTL_ADD, pClient, EPOLLIN);
    }
private:
    CELLEpoll _ep;
};

#endif // !_CELLEpollServer_HPP_

在和接收客户端连接的server端引入epoll

继承EasyTcpServer类

EasyEpollServer.hpp

#ifndef _EasyEpollServer_hpp_
#define _EasyEpollServer_hpp_

#include"EasyTcpServer.hpp"
#include"CELLEpollServer.hpp"
#include"CELLEpoll.hpp"

class EasyEpollServer : public EasyTcpServer
{
public:
    void Start(int nCELLServer)
    {
        EasyTcpServer::Start<CELLEpollServer>(nCELLServer);
    }
protected:
    //处理网络消息
    void OnRun(CELLThread* pThread)
    {
        CELLEpoll ep;
        ep.create(1);
        ep.ctl(EPOLL_CTL_ADD, sockfd(), EPOLLIN);
        while (pThread->isRun())
        {
            time4msg();
            //---
            int ret = ep.wait(1);
            if (ret < 0)
            {
                CELLLog_Error("EasyEpollServer.OnRun ep.wait exit.");
                pThread->Exit();
                break;
            }
            //---
            auto events = ep.events();
            for(int i = 0; i < ret; i++)
            {
                //当服务端socket发生事件时,表示有新客户端连接
                if(events[i].data.fd == sockfd())
                {
                    if(events[i].events & EPOLLIN)
                    {
                        Accept();
                    }
                }
            }
        }
    }
};

#endif // !_EasyEpollServer_hpp_

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top