ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • epoll server chatting app
    소프트웨어 및 프로그래밍/네트워크 프로그래밍 2020. 3. 26. 11:07

    https://jacking75.github.io/choiheungbae/%EB%AC%B8%EC%84%9C/epoll%EC%9D%84%20%EC%82%AC%EC%9A%A9%ED%95%9C%20%EB%B9%84%EB%8F%99%EA%B8%B0%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.pdf

     

    select

    fd_set : 고정 비트 테이블 사용, 크기가 고정

    이벤트가 발생 감재를 위해서는 순차검색, O(n)

    데이터가 오면 기존 fd_set을 모두 변경

     

    epoll

    fd의 수가 무제한

    fd를 커널에서 관리, 상태가 바뀐 것만을 직접 통지 --> O(1)

    fd_set 복사 불필요

     

    epoll 함수

    epoll_create

    epoll_ctl

    epoll_wait

     

    epoll_create

    int fd_epoll;
    bool is_epoll_init = false;
    int EpollInit(int size)
    {
      if((fd_epoll = epoll_create(size)) > 0) is_epoll_init = true;
      return fd_epoll;
    }
    

    int epoll_create(int size);

    size 값은 정수인데 무작정 큰 수를 쓸 수는 없다.
    • 예상되는 최대 동시접속 수로 한다.
    • 운영체제가 이 숫자를 허용하는지 먼저 확인해야 한다.
    • 서버의 한계(ServerLimits)를 숙지하고, 적당한 값을 써 주거나 서버한계를 늘려야 한다.

     

    epoll_ctl

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

    int EpollAdd(const int fd)
    {
      struct epoll_event ev;
      ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
      ev.data.fd = fd;
      return epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd, &ev);
    }

    int op에 들어가는 flag

    EPOLL_CTL_ADD  : fd를 epfd의 관심 목록에 추가, 이미 목록에 존재한다면 EEXIST 에러를 발생, event 집한은 *ev에 저장

    EPOLL_CTL_MOD : *ev에 지정된 정보를 이용해 fd 설정 변경, 관심 목록에 없는 fd라면 ENOENT 에러를 발생

    EPOLL_CTL_DEL   : epfd에서 fd를 제거, epfd 관심 목록에 없는 fd를 제거하려면 ENOENT 에러를 발생, fd를 닫으면 epoll 관심 목록에서 자동 제거

     

     

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

     

    관심 있는 fd들에 무슨 일이 일어났는지 조사, 사건들의 리스트를 (epoll_event).events[]의 배열로 전달.

    실제 동시 접속수와는 상관없이 maxevents 파라미터로 최대 몇 개까지의 event만 처리할 것임을 지정해 주도록 하고 있음

     

    maxevnets 파라미터를 통해 하번에 처리할 숫자를 제한

     

    timeout 밀리세컨드 단위로 지정, 해당 시간 동안 사건 발생 기다림, 기다리는 도중 사건이 발생하면 즉시 리턴. 여기서 -1 을 할당하면 영원히 기다림(blocking), 0을 대입하면 polling과 비슷

     

    #define MAX_EVENTS 100 // 최대 100개를 한번에 처리할 것이다.
    struct epoll_event events[MAX_EVENTS];
    int nfds, n;
    
    for(;;){
      // 발생한 사건의 갯수를 얻어낸다. 0인 경우는 아무 일도 발생하지 않은 것
      nfds = epoll_wait(fd_epoll, events, MAX_EVENTS, 10);
      if(nfds < 0) {
        // critical error
        fprintf(stderr, "epoll_wait() error : %s\n", strerror(errno));
        exit(-1);
      }
      
      // 아무 일도 일어나지 않았다.
      if(nfds == 0){
        // idle
        continue;
      }
      for(n=0; n < nfds; ++n) OnEvent(&events[n]);
    }
    
    int OnEvent(const struct epoll_event *event)
    {
      int nread;
      char buf[1024];
    
      if( event->events & EPOLLIN ){
        nread = read(event->data.fd, buf, 1024);
        
        if( nread < 1){
          fprintf(stdout, "nread returns : %d\n", nread);
        } else {
          fprintf(stdout, "data : %s\n", buf);
          buf[0] = 0;
        }
      }
      if( event->events & EPOLLOUT){
    
      }
      if( event->events & EPOLLERR){
      }
      return 1;
    }

     

    EPOLLIN : 수신할 데이터가 존재하는 상황, EPOLL_CTL의 입력, WAIT의 출력에 모두 사용됨

    EPOLLOUT : 출력버퍼가 비워져서 당장 데이터를 전송할 수 있는 상황, EPOLL_CTL의 입력, WAIT의 출력에 모두 사용됨

    EPOLLPRI : OOB 데이터가 수신된 상황, EPOLL_CTL의 입력, WAIT의 출력에 모두 사용됨

    EPOLLRDHUP : 연결이 종료되거나 Half-close가 진행된 상황, 이는 엣지 트리거 방식에서 유용하게 사용됨, 상대편 소켓 셧다운, WAIT의 출력에 모두 사용됨

     

    EPOLLERR : 에러가 발생한 상황, EPOLL_WAIT의 출력으로만 사용됨

    EPOLLHUP : 장애발생, EPOLL_WAIT의 출력으로만 사용됨

     

    EPOLLET : 이벤트의 감지를 엣지 트리거 방식으로 동작, EPOLL_CTL 입력에만 사용됨

    EPOLLONESHOT : 이벤트가 한번 감지가 되면, 해당 파일 디스크립터에서는 더 이상 이벤트를 발생시키지 않는다. 따라서 epoll_ctl 함수의 두번째 인자로 EPOLL_CTL_MOD를 전달해서 이벤트로 재설정, EPOLL_CTL 입력에만 사용됨

     

    https://gist.github.com/jacking75/6e8cef4141e82811c806

     

    epoll을 사용한 echo 서버

    epoll을 사용한 echo 서버. GitHub Gist: instantly share code, notes, and snippets.

    gist.github.com

    https://github.com/RajivKurian/epoll-example

     

     

    Edge Trigger 과 Level Trigger

     

    epoll에서는 Edge Trigger와 level Trigger 둘 중 하나를 선택

    기본은 Level Trigger

     

    Level Trigger는 특정 준위가 유지되는 동안 감지

    Edge Trigger는 특정 준위가 변화하는 시점에서만 감지

     

     

     

Designed by Tistory.