不改变整体流程,把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_