Multiplexor::Multiplexor(int size, int timeout, bool lt)
{
m_epfd = epoll_create(size);
if (m_epfd == -1)
throw HERM_SOCKET_EXCEPTION(ST_OTHER);
m_size = size;
m_evts = new struct epoll_event[size];
m_timeout = timeout;
// sys/epoll.h is no EPOLLRDHUP(0X2000), don't add EPOLLRDHUP
m_otherMasks = EPOLLERR | EPOLLHUP;
if (!lt)
m_otherMasks |= EPOLLET;
}
Multiplexor::~Multiplexor()
{
close(m_epfd);
delete[] m_evts;
}
void Multiplexor::Run()
{
int fds = epoll_wait(m_epfd, m_evts, m_size, m_timeout);
if (fds == -1)
{
if (errno == EINTR)
return;
}
for (int i = 0; i < fds; ++i)
{
__uint32_t evts = m_evts[i].events;
ISockHandler* eh = reinterpret_cast(m_evts[i].data.ptr);
int stateType = ST_SUCCESS;
if (evts & EPOLLIN)
stateType = eh->OnReceive();
if (evts & EPOLLOUT)
stateType = eh->OnSend();
if (evts & EPOLLERR || evts & EPOLLHUP)
stateType = ST_EXCEPT_FAILED;
if (stateType != ST_SUCCESS)
eh->OnError(stateType, errno);
}
}
void Multiplexor::Register(ISockHandler* eh, MultiplexorMask mask)
{
MultiplexorMask masks = mask | m_otherMasks;
OperateHandler(EPOLL_CTL_ADD, eh, masks);
}
void Multiplexor::Remove(ISockHandler* eh)
{
// Delete fd from epoll, don't need masks
OperateHandler(EPOLL_CTL_DEL, eh, ALL_EVENTS_MASK);
}
void Multiplexor::EnableMask(ISockHandler* eh, MultiplexorMask mask)
{
MultiplexorMask masks = mask | Herm::READ_MASK | Herm::WRITE_MASK;
OperateHandler(EPOLL_CTL_MOD, eh, masks | m_otherMasks);
}
void Multiplexor::DisableMask(ISockHandler* eh, MultiplexorMask mask)
{
MultiplexorMask masks = (Herm::READ_MASK | Herm::WRITE_MASK) & (~mask);
if (!OperateHandler(EPOLL_CTL_MOD, eh, masks | m_otherMasks))
throw HERM_SOCKET_EXCEPTION(ST_OTHER);
}
上面类就用到epoll_create(), epoll_ctl()和epoll_wait(),以及几种事件。epoll用起来比select清爽一些。
大致用法类似下面这样:
先定义一个Handler
class StreamHandler : public Herm::ISockHandler
{
public:
virtual Herm::Handle GetHandle() const;
virtual int OnReceive(int);
virtual int OnSend(int);
};
在OnReceive()处理收到数据的动作,在OnSend()。。。。
在通信线程中,大概类似这样的代码,实际看情况。
Multiplexor multiplexor;
StreamHandler sh;
multiplexor.Register(&sh, READ_EVT);
multiplexor.Run(...);