Epoll
select의 문제점
- select 호출 후에 모든 파일 디스크립터를 대상으로 하는 반복문
- select에 매번 전달해야하는 관찰 대상 정보
Epoll 개요
리눅스 환경에서 사용가능한 select의 단점을 개선한 기술이다. 아래와 같은 함수를 사용한다.
struct epoll_event
{
__uint32_t events; // 이벤트
epoll_data_t data;
}
// 이벤트 종류
EPOLLIN // 수신 데이터 존재
EPOLLOUT // 출력 버퍼 EMPTY
EPOLLPRI // OOB 수신
EPOLLRDHUP // 연결 종료 OR HALF-CLOSE
EPOLLERR // 에러 발생
EPOLLET // 엣지 트리거 방식 이벤트 감지
EPOLLONESHOT // 한 번 발생 이후 발생하지 않음
int epoll_create(int size); // epoll 파일 디스크립터 생성, size는 참고용이다. 리눅스 버전이 2.6.8 이상이면 완전히 무시된다.
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event); // 관찰 대상 등록
// op(관찰 대상 지정 옵션)
EPOLL_CTL_ADD // epoll에 등록
EPOLL_CTL_DEL // epoll에서 삭제
EPOLL_CTL_MOD // 파일 디스크립터의 이벤트 변경
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout); // 관찰, timeout = -1이면 이벤트 발생 까지 무한 대기, 이벤트가 발생한 파일 디스크립터 수를 반환한다. 실패시 -1
레벨 트리거 & 엣지 트리거
- 레벨 트리거 : 활성화 상태(입력버퍼에 데이터가 있는 상태)면 이벤트 등록 => 상태 중심
- 엣지 트리거 : 비활성화 상태에서 활성화 상태가 되었을 때만 이벤트 등록 => 변화 중심
소켓의 기본값은 레벨 트리거다. 엣지 트리거로 변경하면 두 가지를 알아야한다.
- errno를 이용한 오류 원인 파악 - ex: read가 읽을 것이 없다면 errno에는 EAGAIN이 저장된다.
- Non-blocking IO 소켓 ```c++ int fcntl(int fildes, int cmd, …); // cmd에 따라 값을 반환, 실패시 -1
// Non-blocking 설정 int flag = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flag | O_NONBLOCK);
```
엣지 트리거를 사용할 경우 데이터 수신과 데이터 처리 시점을 분리할 수 있다.