In-depth understanding of epoll

overview

In network programming, efficiently handling a large number of concurrent connections is a key issue. The epoll mechanism provided by Linux has become an important tool to solve this problem. epoll is an I/O event notification mechanism, which realizes high-performance event-driven concurrent programming through three main functions, namely epoll_create, epoll_ctl and epoll_wait. Let's take a deeper look at these three functions and how to use them.

1. epoll_create - create an epoll instance

int epoll_create(int size);

size: The number of listener nodes of the created red-black tree. (For kernel reference only.)
Return value: fd pointing to the root node of the newly created red-black tree.
-1: represents an error

2. epoll_ctl - controls the events of the epoll instance

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epfd: the return value of the epoll_create function. epfd
op: the operation performed on the monitored red and black numbers.
EPOLL_CTL_ADD Add fd to listen to the red-black tree
EPOLL_CTL_MOD Modify fd to listen to the listening events on the red-black tree.
EPOLL_CTL_DEL Remove an fd from the monitoring red-black tree (cancel monitoring)
fd: the fd to be monitored
event: the essence struct epoll_event structure pointer
return value: success 0; failure: -1 errno

Structure introduction

struct epoll_event {
    
    
		__uint32_t events; /* Epoll events */
		epoll_data_t data; /* User data variable */
	};
	typedef union epoll_data {
    
    
		void *ptr;
		int fd;
		uint32_t u32;
		uint64_t u64;
	} epoll_data_t;

events value:

EPOLLIN: Indicates that the corresponding file descriptor can be read (including the normal closing of the peer SOCKET)
EPOLLOUT: Indicates that the corresponding file descriptor can be written
EPOLLERR: Indicates that the corresponding file descriptor has an error
, etc. (not important)

data: union (community):

int fd; fd void *ptr corresponding to the listening event
; callback function
uint32_t u32;
uint64_t u64;

3. epoll_wait - wait for an event to occur

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

The epoll_wait function is used to wait for the event to occur, and when the event occurs, it will return the ready file descriptor and the corresponding event type. Parameters include:

epfd: the return value of the epoll_create function. epfd

events: Outgoing parameters, [array], those fd structures that meet the monitoring conditions.

maxevents: The total number of elements in the above array. eg:struct epoll_event evnets[1024]->1024

timeout:
-1: blocking
0: not blocking
Greater than 0: timeout (milliseconds)
return value:
greater than 0: the total number of listeners. Can be used as a loop cap.
0: No fd satisfies the listening event
-1: Failed. errno

insert image description here

pseudocode

For code implementation, please refer to: Link
epoll to realize multi-channel IO transfer ideas:

lfd = socket();			监听连接事件lfd
bind();
listen();

int epfd = epoll_create(1024);				epfd, 监听红黑树的树根。

struct epoll_event tep, ep[1024];			tep, 用来设置单个fd属性, ep 是 epoll_wait() 传出的满足监听事件的数组。

tep.events = EPOLLIN;					初始化  lfd的监听属性。
tep.data.fd = lfd

epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &tep);		将 lfd 添加到监听红黑树上。

while (1) {
    
    

	ret = epoll_wait(epfd, ep,1024-1);			实施监听

	for (i = 0; i < ret; i++) {
    
    
		
		if (ep[i].data.fd == lfd) {
    
    				// lfd 满足读事件,有新的客户端发起连接请求

			cfd = Accept();

			tep.events = EPOLLIN;				初始化  cfd的监听属性。
			tep.data.fd = cfd;

			epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &tep);

		} else {
    
    						cfd 们 满足读事件, 有客户端写数据来。

			n = read(ep[i].data.fd, buf, sizeof(buf));

			if ( n == 0) {
    
    

				close(ep[i].data.fd);

				epoll_ctl(epfd, EPOLL_CTL_DEL, ep[i].data.fd , NULL);	// 将关闭的cfd,从监听树上摘下。

			} else if (n > 0{
    
    --write(ep[i].data.fd, buf, n);
			}
		}
	}

Summarize

By using the three main functions epoll_create, epoll_ctl and epoll_wait, we can make full use of Linux's epoll mechanism to achieve efficient event-driven concurrent programming. First, by creating an epoll instance, we can monitor multiple file descriptors. Then, use the epoll_ctl function to add, modify, and delete events that need to be monitored. Finally, wait for events to occur and process ready file descriptors by calling the epoll_wait function.

Reasonable use of these functions can help us effectively manage a large number of concurrent connections and improve system performance and responsiveness. Of course, in practical applications, we also need to combine other network programming knowledge and skills to achieve more stable and efficient network applications

Guess you like

Origin blog.csdn.net/qq_46017342/article/details/132308231