2016년 5월 29일 일요일

뇌자극 TCP_IP 프로그래밍 17강 요약

1.  epoll 소개

epoll은 event + poll의 합성어다. 대용량의 데이터를 처리하기 위해서 입출력 다중화 기술의 장점을 계승하며, 단점을 보완했다.
입출력 다중화의 결정적인 문제는 비트 테이블을 순환하면서 어떤 파일에 데이터 변화가 있는지 확인해야 한다는 것이였다.

epoll은 입출력 다중화 처럼 관심 있는 파일 목록을 poll에 유지한다.
poll에 있는 파일에 데이터 변화가 생기면 이벤트가 발생하고
이벤트를 받은 프로그램은 poll에서 이벤트가 발생한 파일 목록을 가져올 수 있다.
이 poll은 파일의 데이터 변화를 이벤트로 관리하므로 이벤트 풀이라고 한다.

2. epoll 사용법

1) 적당한 크기의 이벤트 풀을 만든다.
2) 이벤트를 관리해야 하는 파일이 들어오면 이벤트 풀에 집어 넣는다.
3) 이벤트 풀에서 이벤트가 발생하기를 기다린다.
4) 이벤트가 발생하면, 이벤트가 발생한 파일의 목록을 가져오고 읽기/쓰기 작업을 한다.

이벤트 풀의 생성

#include <sys/epoll.h>
int epoll_create(int size);

size : 이벤트 풀의 크기

이벤트 풀 관리

이벤트 풀의 관리할 파일을 넣고 빼는 작업

#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

-efpd : epoll_create 함수로 만든 epoll 기술자다
-op : 이벤트 풀의 관리 명령을 지정한다.
   EPOLL_CTL_ADD : 관리하고자 하는 파일 지정 번호 fd를 efpd가 가리키는 이벤트 풀에 추가한다. 추가된 파일에 이벤트가 발생하면 이벤트 풀에 전달된다.
   EPOLL_CTL_MOD : 지정한 FD에 대해서 event 의 정보를 변환한다.
   EPOLL_CTL_DEL : 파일 지정 번호 fd를 이벤트 풀에서 제거한다.
-event : 검사할 이벤트 종류를 지정하기 위해서 사용하는 구조체
   EPOLLIN  : 입력이벤트를 검사한다.
   EPOLLOUT : 출력 이벤트를 검사한다.
   EPOLLERR : 에러 이벤트를 검사한다.
   EPOLLHUP : 데이터 송수신 지체 이벤트를 검사한다.

이벤트 관리

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

-epfd : epoll_create 함수로 만든 이벤트 풀의 지정번호
-event : 이벤트가 발생한 파일의 정보는 epoll_event 구조체로 넘어온다.
-maxevetns : 한번에 가져올 수 있는 이벤트의 크기를 지정한다. 0보다 커야 하고, events 배열의 크기를 초과하면 안된다.
-timeout : 기다릴 시간을 밀리 초 단위로 지정한다. -1을 지정하면 이벤트가 발생할 때까지 무한정 기다리고, 0을 지정하면 이벤트를 기다리지 않고 즉시 반환한다.

3. epoll 네트워크 프로그래밍

프로그램의 흐름

1) socket() -> bind() -> listen() 순서로 듣기 소켓을 만든다.
2) epoll_ctl 함수로 듣기 소켓을 이벤트 풀에 추가한다.
3) epoll_wait 함수로 이벤트를 기다린다.
4) 발생한 이벤트를 검사한다.
5) 만약 듣기 소켓에서 이벤트가 발생하면
   (1) accept 함수를 호출해서 연결 소켓을 만든다.
   (2) epoll_ctl 함수로 연결 소켓을 이벤트 풀에 추가한다.
   (3) 3)으로 돌아간다.
6)만약 연결 소켓에서 이벤트가 발생했다면
   (1) read/write 함수로 클라이언트와 통신한다.
   (2) 클라이언트 종료 이벤트라면 이벤트 풀에서 연결 소켓을 제거한다.
   (3) 3)으로 돌아간다.

4. epoll의 장점과 단점

장점
- 멀티 스레드, 멀티 프로세스 방식에 비해서 매우 효율적으로 작동한다.
- 데이터 변경이 있는 파일을 찾기 위해 루프를 돌 필요가 없다.

단점
- 데이터 처리에 오랜 시간이 걸리는 서비스에는 적당하지 않다.

5. 리얼 타임 시그널로 대용량 데이터 처리하기

시그널의 특징

-시그널은 대기열이 없다 : 대기열이 없기에 한 번에 2개 이상의 시그널이 입력되면 뒤에 도착한 시그널은 잃어 버리게 된다.

- 시그널은 부가 정보를 가지지 않는다 : 시그널은 의미만 알려주고 어떤 정보도 포함하지 않는다. 어떤 파일에서 어떤 종류의 이벤트가 발생했는지의 정보도 필요하다.

리얼 타임 시그널

시그널의 단점을 개선한 기법이다. 다음과 같은 특징이 있다.

-대기열을 가진다 : 시그널을 저장하기 위한 대기얼을 가지고 있다. 두 개 이상의 시그널이 동시에 도착해도 잃어버리지 않고 전달된다.

-부가 정보를 가진다 : 시그널 번호, 시그널이 발생한 파일 지정 번호, 시그널이 발생한 이유, 프로세스 ID, 유저 ID 등 다양한 정보를 함께 전달한다.

리얼 타임이 사용하는 siginfo 구조체의 모습이다.

typedef struct siginfo {
  int si_sinno;
  int si_errno;
  int si_code;
  pid_t si_pid;
  uid_t si_uid;
  void *si_addr;
  uinon sigval si_value;
  union{
    struct {
      int _band;
      int _fd;
    } _sigpoll;
  }_sifields;
}  siginfo_t;

리얼 타임 시그널 대기

#include <signal.h>
int sigwaitinfo(const sigset_t *set, siginfo_t *info);
int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec timeout);

-sigset_t : 이들 함수는 sigset_t 에 설정된 시그널을 가진다.
-siginfo_t : 시그널이 전달되면 siginfo_t 구조체의 포인터를 반환한다. 여기에는 리얼 타임 시그널과 관련된 정보를 포함하고 있다.
-timeout : sigtimewait 함수는 timeout에 지정된 시간만큼 기다린다. 만약 timeout 시간 안에 시간이 없으면 바로 반환한다.

6. 리얼 타임 시그널과 소켓 프로그래밍

프로그램의 흐름

1) sigemptyset() -> sigaddset() -> sigprocmask() 로 리얼 타임 시그널을 설정한다.
2) socket() -> bind() -> listen() 으로 흐름은 같다.
3) 듣기 소켓을 비봉쇄/비동기 소켓으로 만든다.
4) 듣기 소켓이 리얼 타임 시그널을 발생하도록 설정한다.
5) sigwaitinfo 함수로 소켓 이벤트를 기다린다.
6) 만약 듣기 소켓에서 발생한 이벤트라면
   (1) accept 함수를 호출해서 연결 소켓을 만든다.
   (2) 소켓을 비봉쇄/비동기 소켓으로 만들어서 리얼 타임 시그널을 발생하도록 설정한다.
7) 만약 연결 소켓에서 발생한 이벤트라면 소켓 데이터를 읽어서 처리한다.

소스 코드를 보고 해보는게 이해가 가장 빠르다

소스 코드 받기

댓글 없음:

댓글 쓰기