어떻게 C 로 웹 서버 의 I/O 다 중 재 활용 을 씁 니까?

7597 단어 cwebi/o
머리말
I/O 모델
socket 프로 그래 밍 을 접 한 학생 들 은 모두 I/O 모델 의 개념 을 알 아야 한다.Liux 에는 I/O,비 차단 I/O,I/O 다 중 재 활용,신호 구동 I/O 와 비동기 I/O 다섯 가지 모델 이 있다.
다른 모델 의 구체 적 인 개념 은 여기 서 소개 하지 않 고 자신 이 이해 하 는 I/O 다 중 재 활용 만 간단하게 제시 합 니 다.쉽게 말 하면 하나의 프로 세 스 로 여러 개의 socket 을 관리 하 는 것 입 니 다.곧 여러 개의 socket 을 하나의 표 에 넣 을 것 입 니 다.그 중에서 socket 이 조작 할 수 있 을 때 프로 세 스 에 알 리 고 처리 하 는 것 입 니 다.I/O 다 중 재 활용 의 실현 방식 은 select,poll 과 epoll 이 있 습 니 다.
select/poll/epoll
Liux 에서 파일 설명자(file descriptor,하 fd)를 통 해 socket 작업 을 하기 때문에 다음 글 은 모두 fd 작업 입 니 다.
먼저 처음에 실 현 된 select 의 문 제 를 말 합 니 다.
4.567917.select 에서 열 린 fd 의 최대 수량 은 제한 이 있 고 보통 1024 이 며 현재 계산 시스템 의 병발 량 전에 약간 적용 되 지 않 습 니 다
  • select 는 fd 가 조작 할 수 있다 는 통 지 를 받 았 을 때 구체 적 으로 어떤 fd 인지 알 수 없고 선형 으로 fd 표를 스 캔 해 야 하 며 효율 이 비교적 낮다
  • fd 가 조작 할 수 있 을 때 fd 는 fd 시 계 를 커 널 로 복사 하여 옮 겨 다 니 며 소모 도 비교적 크다
  • 네트워크 기술 의 발전 에 따라 poll:poll 은 select 에 비해 pollfd 표(링크 구현)를 사용 하여 fd 를 대체 하 였 으 며,상한 선 이 없 지만,시스템 메모리 의 제한 을 받 아 fd 를 옮 겨 다 니 는 방식 으로 병행 할 때 효율 은 여전히 문제 이다.
    마지막 으로 epoll 은 Linux 2.6 의 커 널 에 출시 되 었 습 니 다.이벤트 체 제 를 사용 하여 모든 fd 에 이 벤트 를 추가 합 니 다.fd 의 이벤트 가 실 행 될 때 리 셋 함수 로 대응 하 는 이 벤트 를 처리 합 니 다.epoll 의 장점 은 다음 과 같 습 니 다.
    4.567917.활발 한 fd 에 만 관심 을 가지 고 정확 한 포 지 셔 닝 을 하여 poll 의 시간 효율 O(n)에서 O(1)로 바 꾸 었 다
  • fd 수량 제한 은 시스템 이 열 수 있 는 최대 파일 수 입 니 다.시스템 메모리 와 모든 fd 소모 메모리 의 영향 을 받 을 수 있 습 니 다.현재 시스템 하드웨어 설정 으로 병행 수량 은 절대 문제 가 되 지 않 습 니 다
  • 4.567917.커 널 은 메모리 맵 을 사용 하고 대량의 fd 가 내부 핵 상태 로 전송 하 는 것 은 더 이상 문제 가 되 지 않 습 니 다한 걸음 에 도착 하기 위해 서도 가장 선진 적 인 I/O 다 중 재 활용 모델 을 배우 기 위해 epoll 체 제 를 직접 사 용 했 습 니 다.다음은 epoll 관련 기초 와 자신의 서버 의 실현 과정 을 소개 합 니 다.
    epoll 소개
    epoll 은파일 을 도입 해 야 합 니 다.먼저 epoll 시리즈 함 수 를 소개 합 니 다.
    epoll_create
    int epoll_create(int size);
    epoll 인 스 턴 스 를 만 들 고 이 epoll 인 스 턴 스 를 가리 키 는 파일 설명 자 를 되 돌려 줍 니 다.epoll 인 스 턴 스 를 더 이상 사용 하지 않 을 때 close()방법 으로 닫 아야 합 니 다.
    최초의 실현 에서 size 는 시스템 이 충분 한 공간 을 분배 할 수 있 도록 열 려 있 는 최대 fd 수로 들 어 옵 니 다.최신 버 전의 커 널 에서 시스템 커 널 동적 할당 메모리 에는 더 이상 이 매개 변수 가 필요 하지 않 습 니 다.그러나 프로그램 이 오래된 커 널 에서 실행 되 는 데 문제 가 있 는 것 을 피하 기 위해 서 는 이 값 이 0 이상 이 어야 합 니 다.
    epoll_ctl
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    epfd 는 epollcreate 에서 돌아 오 는 파일 설명자
  • op 은 파일 설명자 감청 사건 의 조작 방식,EPOLLCTL_ADD/EPOLL_CTL_MOD/EPOLL_CTL_DEL 은 각각 감청 사건 을 추가,수정,삭제 하 는 것 을 표시 합 니 다
  • fd 는 감청 할 파일 설명자 입 니 다4.567917.이 벤트 는 감청 할 사건 으로 선택 할 수 있 는 사건 과 행 위 는 아래 에서 설명 합 니 다그것 의 구 조 는 다음 과 같다.
    
    typedef union epoll_data {
       void        *ptr;
       int          fd;
       uint32_t     u32;
       uint64_t     u64;
    } epoll_data_t;
    
    struct epoll_event {
       uint32_t     events;      /* epoll   */
       epoll_data_t data;        /*        */
    };
    epoll_wait
    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); epoll 이벤트 감청:
    4.567917.이 벤트 는 epoll 이벤트 배열 이 고 epoll 이벤트 의 구조 에 대해 이미 소개 되 었 습 니 다4.567917.maxevents 는 감청 으로 얻 은 최대 사건 수 입 니 다
  • timeout 은 한 번 의 감청 에서 사건 을 얻 지 못 하 는 가장 긴 대기 시간 으로-1 로 설정 하면 기다 리 는 것 을 계속 막 고 0 으로 설정 하면 바로 돌아 갑 니 다
  • epoll 행동
    epoll 에서ctl 의 이벤트 매개 변수 에서 이벤트 이 벤트 는 다음 과 같은 옵션 이 있 습 니 다.
    EPOLLIN(읽 기 가능),EPOLLOUT(쓰기 가능),EPOLLRdhup(연결 종료),EPOLLPRI(긴급 데이터 읽 기 가능),그 밖 에 EPOLLERR(오류),EPOLLHUP(연결 끊 기)사건 은 epoll 기본 값 으로 계속 감청 됩 니 다.
    이벤트 설정 외 에 감청 행위 도 설정 할 수 있 습 니 다.
  • level trigger:이 행 위 는 epoll 에 의 해 기본적으로 지원 되 며 설정 할 필요 가 없습니다.epoll 에서wait 에서 이 벤트 를 받 았 을 때 프로그램 이 이 사건 을 처리 하지 않 으 면 level trigger 모드 에서 epollwait 는 이벤트 가 프로그램 에 처 리 될 때 까지 이 사건 을 계속 촉발 합 니 다
  • EPOLLET(edge trigger):edge trigger 모드 에서 이 벤트 는 epollwait 가 한 번 촉발 합 니 다.사용자 가 이 사건 을 처리 하지 않 으 면 다음 epollwait 다시 터치 합 니 다.적절하게 처리 한 상황 에서 이 모델 은 의심 할 여지없이 효율 적 이다.주의해 야 할 것 은 이 모드 는 socket 처리 비 차단 모드 가 필요 합 니 다.다음은 이 모드 를 실현 합 니 다
  • EPOLLONESHOT:1 차 명중 모드 에서 같은 파일 설명자 에 게 같은 유형의 사건 은 한 번 만 발생 합 니 다.반복 적 으로 트리거 하려 면 파일 설명자 에 이 벤트 를 다시 등록 해 야 합 니 다
  • EPOLLWAKEUP:3.5 버 전이 추가 되 었 습 니 다.단일 명중 과 ET 모드 가 설정 되 어 있 고 프로 세 스 가 휴면 각성 능력 이 있 으 면 이벤트 가 걸 리 고 처 리 될 때 이 옵션 을 사용 하면 시스템 이 일시 정지 또는 휴면 상태 에 들 어가 지 않도록 합 니 다.이벤트 피 epollwait 조정 후 다음 epoll 까지wait 이 이벤트,파일 설명 자 를 다시 조정 하면 종료 되 고 이벤트 가 취소 되 거나 수정 되 며 처리 중인 상태 로 여 겨 집 니 다
  • EPOLLEXCLUSIVE:4.5 버 전 을 추가 하여 대상 파일 설명자 와 연 결 된 epoll 핸들 에 독점 깨 우기 모드 를 설정 합 니 다.대상 파일 설명자 가 여러 개의 epoll 핸들 에 연결 되 어 있 으 면 깨 우기 이벤트 가 발생 했 을 때 기본 모든 epoll 핸들 이 깨 어 납 니 다.이 표 지 를 설정 한 후에 epoll 핸들 중 하나 가 깨 어 나'놀 라 움'현상 을 피 할 수 있 습 니 다
  • 감청 이벤트 와 행위 수요 가 동시에 설정 되 었 을 때 연산 자|를 사용 하면 됩 니 다.
    코드 구현
    전체 처리 논리
    epoll 을 사용 할 때 서버 수리 클 라 이언 트 요청 논 리 는 다음 과 같 습 니 다.
    1.서버 socket 을 만 들 고 서버 socket 읽 기 이 벤트 를 등록 합 니 다.
    2.클 라 이언 트 가 서버 에 연결 하여 서버 socket 을 읽 을 수 있 도록 촉발 하고 서버 가 클 라 이언 트 socket 을 만 들 고 클 라 이언 트 socket 읽 기 이 벤트 를 등록 합 니 다.
    3.클 라 이언 트 가 데 이 터 를 보 내 고 클 라 이언 트 socket 을 읽 을 수 있 도록 촉발 합 니 다.서버 가 클 라 이언 트 정 보 를 읽 고 응답 을 socket 에 기록 합 니 다.
    4.클 라 이언 트 가 연결 을 닫 고 클 라 이언 트 socket 을 읽 을 수 있 도록 촉발 합 니 다.서버 가 클 라 이언 트 정 보 를 읽 는 것 이 비어 있 고 클 라 이언 트 socket 읽 기 이 벤트 를 취소 합 니 다.
    
    erver_fd = server_start();
    epoll_fd = epoll_create(FD_SIZE);
    epoll_register(epoll_fd, server_fd, EPOLLIN|EPOLLET);//     socketEPOLL   ET  
    
    while (1) {
        event_num = epoll_wait(epoll_fd, events, MAX_EVENTS, 0);
        for (i = 0; i < event_num; i++) {
            fd = events[i].data.fd;
            //       socket  ,       
            if ((fd == server_fd) && (events[i].events == EPOLLIN)){
                accept_client(server_fd, epoll_fd);
            //       socket  ,       ,     
            } else if (events[i].events == EPOLLIN){
                deal_client(fd, epoll_fd);
            } else if (events[i].events == EPOLLOUT)
                // todo     ,           
                continue;
        }
    }
    주의해 야 할 것 은 클 라 이언 트 socket 은 읽 을 수 있 는 후에 도 바로 쓸 수 있 습 니 다.저 는 요청 을 직접 읽 은 다음 에 응답 정 보 를 write 에 넣 고 데 이 터 를 읽 을 때 버퍼 가 가득 찬 문 제 를 고려 하지 않 았 습 니 다.
    여기 서 제시 한 해결 방안 은 다음 과 같다.
    1.클 라 이언 트 socket 과 buffer 의 해시 표를 설정 합 니 다.
    2.정보 버퍼 가 가득 찼 을 때 recv 는 EAGIN 오 류 를 되 돌려 줍 니 다.이 때 데 이 터 를 buffer 에 넣 고 응답 하지 않 습 니 다.
    3.후속 읽 기 이벤트 에서 데이터 끝 을 읽 은 후 socket 을 등록 하여 이 벤트 를 쓸 수 있 습 니 다.
    4.쓰기 가능 한 이 벤트 를 처리 할 때 buffer 의 모든 요청 내용 을 읽 고 처리 가 끝 난 후에 클 라 이언 트 에 응답 합 니 다.
    5.마지막 으로 socket 쓰기 이 벤트 를 취소 합 니 다.
    epoll ET(edge trigger)모드 설정
    앞에서 말 했 듯 이 ET 모델 은 epoll 의 효율 적 인 모델 로 사건 은 한 번 만 알려 주지 만 잘 처리 하면 높 은 병행 에 더욱 적 용 될 것 이다.그것 은 socket 이 비 차단 모드 에서 만 사용 할 수 있 습 니 다.여기에서 우 리 는 그것 을 실현 합 니 다.
    
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    //      socket   ,   "   "  
    flags = fcntl(sock_fd, F_GETFL, 0);
    fcntl(sock_fd, F_SETFL, flags|O_NONBLOCK);
    
    .....
    //        socket EPOLL   ET  
    epoll_register(epoll_fd, server_fd, EPOLLIN|EPOLLET);
    저 는 사건 을 처리 한 후에 클 라 이언 트 연결 요청 을 사용 하여 테스트 를 했 습 니 다.ET 모드 에서 사건 이 한 번 만 발생 하 는 현상 을 명확 하 게 설 명 했 습 니 다.앞 뒤 대비 도 는 다음 과 같 습 니 다.


    작은 매듭
    Mac OS X 운영 체제 의 일부 부분 은 FreeBSD 를 바탕 으로 하 는 것 입 니 다.FreeBSD 는 지원 하지 않 습 니 다.MAC 도 지원 하지 않 습 니 다.(비슷 한 kquue 가 있 을 뿐)개발 기 에 가서 개 발 했 습 니 다.가장 기본 적 인 C learner 로 서 printf()와 fflush()두 함수 로 디 버 깅 을 했 습 니 다.오래 하지 않 아 드디어 완 성 했 습 니 다.C 선배 님 께 서 디 버 깅 방식 을 추천 해 주 셨 으 면 좋 겠 습 니 다.
    이상 은 C 로 웹 서버 의 I/O 다 중 재 활용 에 대한 상세 한 내용 입 니 다.C 로 웹 서버 의 I/O 다 중 재 활용 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 시기 바 랍 니 다!

    좋은 웹페이지 즐겨찾기