简单介绍epoll
- epoll的使用是为了将监听fd变化的部分交给linux kernel进行实现,在系统层级实现了IO多路复用,通过事件触发的方式完成后续你想进行的操作。
- 关于epoll的ET/LT触发方式,可以理解为LT是阻塞的,当fd事件来临而你没有处理则会持续通知,而ET方式则是只通知一次,因此ET触发方式效率相较于LT方式会更高。
- epoll中可以使用的fd仅能为系统进行过支持的fd,比如linux计时器的fd与socket fd,而如同你使用open函数打开的file fd则是不行的,因为这种fd内部没有实现过
epoll简单使用例,包含定时器与socket两种监听
#include <iostream>
#include <cstdlib>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <sys/timerfd.h>
static void add_event(int epoll_fd, int fd, int state)
{
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
}
int main(int *argc, char *argv[])
{
int epoll_fd;
struct epoll_event events[1024];
epoll_fd = epoll_create(1024);
if (epoll_fd == -1)
{
std::cout << "Epoll create failed." << std::endl;
exit(-1);
}
int timer_fd;
struct itimerspec timer_spec;
timer_spec.it_value.tv_sec = 1;
timer_spec.it_value.tv_nsec = 0;
timer_spec.it_interval.tv_sec = 0;
timer_spec.it_interval.tv_nsec = 100000000;
timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
timerfd_settime(timer_fd, 0, &timer_spec, NULL);
add_event(epoll_fd, timer_fd, EPOLLIN | EPOLLET);
int server_fd;
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(8090);
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1)
{
std::cout << "Socket create failed." << std::endl;
exit(-1);
}
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
{
std::cout << "Socket bind failed." << std::endl;
exit(-1);
}
if (listen(server_fd, SOMAXCONN) != 0)
{
std::cout << "Socket listen failed." << std::endl;
exit(-1);
}
add_event(epoll_fd, server_fd, EPOLLIN);
while (1)
{
int num = epoll_wait(epoll_fd, events, sizeof(events) / sizeof(events[0]), -1);
for (int i = 0; i < num; i++)
{
if(events[i].data.fd == server_fd)
{
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &len);
if(client_fd == -1)
{
std::cout << "Accept client failed." << std::endl;
}
char ip[32]={0};
inet_ntop(AF_INET, &(client_addr.sin_addr.s_addr), ip, sizeof(ip));
printf("New client connected! ip:%s port:%d\n", ip, ntohs(client_addr.sin_port));
add_event(epoll_fd, client_fd, EPOLLIN);
}
else if (events[i].events & EPOLLIN)
{
if (events[i].data.fd == timer_fd)
{
uint64_t exp;
ssize_t s = read(events[i].data.fd, &exp, sizeof(uint64_t));
assert(s == sizeof(uint64_t));
printf("get timerfd!\n");
}
else
{
}
}
}
}
return 0;
}