NIO 원리 분석(3)

에폴

먼저 epoll의 기본 기능에 대해 알아봅시다.

int s = socket(AF_INET, SOCK_STREAM, 0);
bind(s, ...);
listen(s, ...);

int epfd = epoll_create(...)
epoll_ctl(epfd, ...); //将所有需要监听的socket添加到epfd中

while(1) {
    
    
    int n = epoll_wait(...);
    for(接受到数据的socket) {
    
    
      //处理数据
    }
}

이 코드에는 여러 epoll 관련 함수 메서드가 포함되어 있습니다.

  • epoll_create: 파일 핸들 생성

  • epoll_ctl: epoll 객체에 관리할 연결을 추가/수정/삭제합니다.

  • epoll_wait: 관리하는 연결에서 IO 이벤트를 기다립니다.

1、epoll_create
int epoll_create(int size);

기능 설명: epoll 관련 파일 설명자를 생성하는 데 사용됩니다.

매개변수 크기: epoll의 최하위 계층은 파일 디스크립터를 저장하기 위해 레드-블랙 트리를 사용하고, 레드-블랙 트리의 검색 시간 복잡도는 O(logN)이므로 이 크기의 크기를 제한할 필요가 없습니다. 크기는 0보다 큰 숫자로 설정할 수 있습니다.

반환 값: 성공하면 epoll 관련 파일 설명자를 반환하고, 실패하면 -1을 반환합니다.

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

epoll의 이벤트 등록 기능은 모니터링할 이벤트 유형을 등록하는 데 사용됩니다.

매개변수 :

  • epfd: epoll 특정 파일 설명자, epoll_create()의 반환 값

  • op: 세 개의 매크로로 표현되는 작업을 나타냅니다.

    • EPOLL_CTL_ADD: epfd에 새 fd를 등록합니다.

    • EPOLL_CTL_MOD: 등록된 fd의 청취 이벤트 수정

    • EPOLL_CTL_DEL: epfd에서 fd 삭제

  • fd: 모니터링할 파일 설명자

  • 이벤트: 커널에 수신해야 하는 이벤트를 알려줍니다.

  • 반환 값: 0은 성공을 나타내고, -1은 실패를 나타냅니다.

epoll_event 구조는 문서에 설명된 대로입니다 .

       #include <sys/epoll.h>

       struct epoll_event {
    
    
           uint32_t      events;  /* Epoll events */
           epoll_data_t  data;    /* User data variable */
       };

       union epoll_data {
    
    
           void     *ptr;
           int       fd;
           uint32_t  u32;
           uint64_t  u64;
       };

       typedef union epoll_data  epoll_data_t;

이벤트는 다음 매크로의 모음일 수 있습니다:

  • EPOLLIN: 해당 파일 설명자를 읽을 수 있음을 나타냅니다.

  • EPOLLOUT: 해당 파일 설명자를 쓸 수 있음을 나타냅니다.

  • EPOLLPRI: 해당 파일 설명자에 읽을 수 있는 긴급 데이터가 있음을 나타냅니다.

  • EPOLLERR: 해당 파일 설명자에서 오류가 발생했음을 나타냅니다.

  • EPOLLHUP: 해당 파일 설명자가 중단되었음을 나타냅니다.

  • EPOLLET: EPOLL을 수평 트리거 모드가 아닌 에지 트리거 모드로 설정합니다.

  • EPOLLONESHOT: 하나의 이벤트만 수신합니다. 이 이벤트를 수신한 후에도 여전히 이 이벤트를 모니터링해야 하는 경우 EPOLL에 소켓을 다시 추가해야 합니다.

3、epoll_wait
int epoll_wait(int epfd, struct epoll_event * event, 
               int maxevents, int timeout);

기능 : 이벤트 발생을 모니터링하는 기능으로, epoll이 모니터링하는 이벤트 중 이미 전송된 이벤트가 있는 경우 해당 이벤트를 수집할 수 있다.

매개변수:

  • epfd: epoll 자체에 의해 생성된 파일 설명자, epoll_create 호출의 반환 값

  • event: 미리 공간을 할당해야 하는 구조체 배열이며, epoll은 다가오는 이벤트를 이벤트 배열에 할당합니다.

  • maxevents: 총 이벤트 배열 수를 커널에 알려줍니다.

  • timeout: 타임아웃 시간(밀리초) -1로 설정하면 기능 상태가 차단됩니다.

  • 반환 값: -1이면 실패, 0이면 타임아웃, 성공하면 처리해야 할 이벤트 개수를 반환한다.

epoll의 전체 흐름도는 다음과 같습니다.

여기에 이미지 설명을 삽입하세요.

이전 기사에서 select와 poll에 세 가지 결함이 있다는 것을 논의했는데, epoll 방법은 이러한 문제를 매우 잘 해결합니다.

epoll은 파일 디스크립터를 저장하기 위해 커널의 레드-블랙 트리 데이터 구조를 사용합니다. 레드-블랙 트리 데이터 구조를 추가, 삭제 및 수정하는 시간 복잡도는 O(logn)입니다. 선택/폴링이 소켓을 수신할 때마다, 전체 소켓 목록이 커널 상태로 복사되고 epoll은 epoll_ctl을 사용하여 한 번에 하나의 청취 소켓을 커널 상태로 복사하므로 사용자 공간에서 대량의 데이터 복사 및 메모리 할당이 크게 줄어 듭니다. 커널 상태로.

epoll은 비동기 콜백 메커니즘을 사용합니다. 커널 상태는 준비 대기열을 유지합니다. 소켓이 준비되면 콜백 함수는 커널을 트리거하여 소켓 이벤트를 준비 이벤트 목록에 추가합니다. 사용자가 epoll_wait 함수를 호출하면 이벤트가 발생한 파일 디스크립터의 개수가 반환됩니다. 이 과정에서는 선택/폴링과 같은 소켓 컬렉션의 O(N) 시간 복잡도 폴링이 없습니다. 탐지 효율성이 향상되었습니다.

에지 트리거링 및 레벨 트리거링

epoll은 두 가지 이벤트 트리거 모드를 지원합니다.

  • Edge 트리거 : 모니터링되는 소켓 설명자에서 읽기 가능한 이벤트가 발생하면 서버는 epoll_wait 함수를 호출할 때 한 번만 깨어나고 커널 버퍼에서 모든 데이터를 읽습니다.

  • 수평 트리거 : 모니터링되는 소켓 설명자에서 읽기 가능한 이벤트가 발생하면 서버는 epoll_wait 함수를 호출할 때 계속 깨어나고 커널에서 읽을 데이터가 없을 때까지 깨어나는 것을 멈추지 않습니다.

Guess you like

Origin blog.csdn.net/sinat_28199083/article/details/132687297