Linux epoll is to provide a multiplexing technique, similar to each platform supported by select, just epoll kernel implementations done more optimized to support more than select a file descriptor, of course, support this socket file descriptors such networks. Large concurrent access server on Linux, the current implementations are definitely through epoll.
and thread epoll
There are many developers use epoll time, will open multiple threads to perform data communication, such as a thread dedicated to accept (the early years when I personally use kqueue FreeBSD, since a basic understanding of the internal mechanisms do not have to engage in this), a thread messaging, or are used to transmit and receive separate thread.
Under normal circumstances, accept a separate thread is not necessary, accept for the kernel is concerned, the application reads data from the kernel of a little unfinished SYN queue only. For details, see Part accept:
TCP three-way handshake with the corresponding Berkeley Socket APIs introduced
Receive a separate two threads is not necessary because most of the application server, under normal circumstances, start a thread to send and receive data, send and receive the maximum amount of data bottleneck that card instead of CPU; online access server configured as a network card KM few games will apply for 1G bandwidth, which machine was how much data input and output. So we communicate thread epoll server is enough.
The basic principle of epoll
In order to allow certain friends can read more coherent, I still talk about the basic principles of epoll.
epoll external manifestations and select are the same. He provided READ, WRITE, and events such as ERROR.
Process roughly like this:
1. Application event registered interest to the kernel;
2. kernel under certain conditions, the event notification application;
3. After the application receives the event, according to event type to do the corresponding logic.
Principle Part I tell you, the place is not easy to understand, including the level trigger and edge trigger event use (this can be combined with kqueue References 1. WRITE event, consistent with the principles of) modify the details of the event and WRITE events.
READ event, socket recv buff data, will have to notify the application until the buff is empty.
WRITE event, socket send buff from the full data can be sent to the state, it will always notify the application until full buff.
READ event, socket recv buff data, and notifies the application only once, regardless of the application has not called read api, the next is not notified.
WRITE event, socket send buff from a full state to be able to send data only once notification.
The above explanation does not know if you can understand, we can only say so. Have questions, do some tests. In addition, the details of these things fixed after a few years ago, a few years to do this project is the direct use, it rarely involved in the details, is based on written text to understand and remember, if there is wrong, please correct me ^ - ^.
Use WRITE event
This description also look good. Probably describe, in detail see Reference 1. Roughly like this:
1. The logical layer write data to the application layer sends buff, to register click WRITE epoll event;
2. In this case the application will notify epoll a WRITE event;
3. WRITE event response function, the buff from the sending application layer read data, and then transmitting socket send api.
Because I am in a lot of the actual project, I do not see the use of epoll WRITE event to send data, specifically to talk about. Most of the items are sent directly to the queue polling application, my early projects is so dry.
epoll modification event
For this image I more deeply. Modify event epoll comparison pit father, you can not modify an event alone! How do you say? For example epoll already registered READ & WRITE event, if you want to just re-register at WRITE events and READ events unchanged, epoll_ctl API epoll is impossible, you must register READ & WRITE, this can be seen in the following code. FreeBSD's kqueue at this point to fully meet the requirements of our programmers.
Abstract epoll API
I herm socket epoll package stickers section, so that friends refer to epoll usage. Most of the errors I throw exception code is removed.
Multiplexor (int size, int timeout = -1, bool lt = true);
~ Multiplexor ();
void Run ();
void Register (ISockHandler * eh, MultiplexorMask mask);
void Remove (ISockHandler * eh);
void EnableMask (ISockHandler * eh, MultiplexorMask mask);
void DisableMask (ISockHandler * eh, MultiplexorMask mask);
inline bool OperateHandler (int op, ISockHandler * eh, MultiplexorMask mask)
struct epoll_event evt;
evt.data.ptr = eh;
evt.events = mask;
return epoll_ctl (m_epfd, op, eh-> GetHandle (), & evt) = -1!;
struct epoll_event * m_evts;
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), do not add EPOLLRDHUP
m_otherMasks = EPOLLERR | EPOLLHUP;
if (! lt)
m_otherMasks | = EPOLLET;
Multiplexor :: ~ Multiplexor ()
delete  m_evts;
void Multiplexor :: Run ()
int fds = epoll_wait (m_epfd, m_evts, m_size, m_timeout);
if (fds == -1)
if (errno == EINTR)
for (int i = 0; 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, do not 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);
The above class will use epoll_create (), epoll_ctl () and epoll_wait (), as well as several events. epoll up with refreshing than the select.
Usage substantially similar to the following:
Define a Handler
class StreamHandler: public Herm :: ISockHandler
virtual Herm :: Handle GetHandle () const;
virtual int OnReceive (int);
virtual int OnSend (int);
In OnReceive () operation to process the received data, in OnSend (). . . .
In the communication thread, probably like this code, look at the actual situation.
multiplexor.Register (& sh, READ_EVT);