epoll的数据结构与函数
epoll需要使用struct epoll_event 来记录需要监听的事件,将需要监听的文件描述符记录在epoll_event.data.fd中,将需要监听的事件记录在epoll_event.events中,常见的监听事件包括:
- EPOLLIN:读事件;
- EPOLLOUT:写事件;
- EPOLLRDHUP:读关闭事件,本端调用shutdown(SHUT_RD)或对端调用shutdown(SHUT_WR);
- EPOLLHUP:读写关闭事件,本端调用shutdown(SHUT_RDWR)或本端调用shutdown(SHUT_WR)且对端调用shutdown(SHUT_WR);
- EPOLLERR:文件描述符错误事件;
epoll监听通过三个函数来完成:
- epoll_create(int size):创建epoll实例,也可以使用epoll_create1(int flags)函数,传入的参数实际无意义,只要大于0即可;
- epoll_ctl(int epfd, int op, int fd, struct epoll_event *event):修改epoll实例,op对epoll的操作,常见的操作如下:
- EPOLL_CTL_ADD:将fd的监听事件event添加到epfd上;
- EPOLL_CTL_DEL:将fd的监听事件event从epfd上去除;
- EPOLL_CTL_MOD:修改fd在epfd上的监听事件为event。
epoll_ctl设置的event选项常见的如下: - EPOLLET:设置ET触发模式;
- EPOLLONESHOT:设置只监听一次事件,如果希望再监听事件需要再次使用EPOLL_CTL_ADD添加监听事件。
- epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout):用于等待io事件,timeout设置为-1时,为阻塞模式。
epoll的LT触发模式
epoll默认触发模式是LT触发模式,LT模式下,epoll接收数据不需要一次全部接收,未接收的数据会在下次触发时继续读取。
#include <unistd.h>
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <errno.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <signal.h>
#include <netdb.h>
#include <sys/types.h>
//设置地址可重用
static int setReuseAddr(int fd){
if(fd < 0) return -1;
int on = 1;
if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
return -1;
}
return 0;
}
int main(){
const int port = 9007;
const int MAX_EVENT = 20;
struct epoll_event ev, event[MAX_EVENT];
const char * const local_addr = "127.0.0.1";
struct sockaddr_in server_addr = {
0 };
//初始化socket
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == listenfd) {
std::cout << "create listenfd failed:" << strerror(errno) << std::endl;
return -1;
}
if (setReuseAddr(listenfd) < 0){
std::cout << "set reuse addr failed:" << strerror(errno) << std::endl;
close(listenfd);
return -1;
}
server_addr.sin_family = AF_INET;
inet_aton( local_addr, &(server_addr.sin_addr));
server_addr.sin_port = htons(port);
if (bind(listenfd, (const struct sockaddr *)&server_addr, sizeof (server_addr)) < 0) {
std::cout << "bind port failed:" << strerror(errno) << std::endl;
close(listenfd);
return -1;
}
if (listen(listenfd, 200)</