기본 콘텐츠로 건너뛰기

I/O - epoll

epoll 은 감시해야 하는 fd가 많을 때 select나 poll에 비해 성능이 좋다.

epoll_create() epoll 인스턴스를 생성, 이 인스턴스를 참조하는 fd를 리턴한다.
epoll_ctl() 관심 목록 설정할때 사용. 새 fd를 추가 하거나 기존 목록에서 제고 할 수 있고 이벤트 감시를 변경 할 수 있다.
epoll_wait() 인스턴스에서 준비 목록을 리턴한다.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "sys/epoll.h"
int epoll_create( int size );
// 성공하면 fd 리턴, 에러가 발생하면 -1
// 리눅스 2.6.8이전에는 커널에게 초기 데이터 구조체를 어떻게 설정하는지에 대한 거였다는데..... 이제는 필요 없단다
int epoll_create1() // 대신 이게 새로 생김
int epoll_ctl( int efd, int op, int fd, struct epoll_event* ev );
// 성공하면 fd 리턴, 에러가 발생하면 -1
// fd에는 pipe, pifo, socket, posix message queue, inotify instanc, divice, 다른 epoll 디스크립터등..이 될 수 있다.
// 만약 안되는놈을 지정하면 EPERM 에러를 발생 한다.
struct epoll_event {
    uint32_t events;
    epoll_data_t data;
}
typedef union epoll_data {
    void* ptr;
    int fd;
    uint32_t u32;
    uint64_t u64;
} epoll_data_t;
/** /proc/sys/fs/epoll 디렉토리에 있는 max_user_watches 에서 한도값을 확인 하고 수정 할 수 있다.**/


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 관심 목록에서 자동 제거 된다.


?
1
2
3
4
5
6
7
8
9
10
11
12
#include "sys/epoll.h"
int epoll_wait( int epfd, struct epoll_event* evlist, int maxevents, int timeout );
// 성공하면 준비된 fd count를 리턴 한다.
// 타임 아웃이면 0, 에러면 -1을 리턴
// 준비된 fd는.. evlist가 가리키는 epoll_event구조체 배열로 리턴됨.
// timeout 이 -1이면 epfd의 관심 목록에 있는 fd중 하나에서 이벤트나 시그널이 발생할때까지 블럭
// timeout 이 0이면 epfd에서 현재 이용 할 수 있는 fd가 있는지를 비블로킹 방식으로 검사
// timeout이 0보다 크면, epfd중 fd하나에서 이벤트나 시그널이 발생할때까지 timeout 밀리초만큼 블록 한다.
//** 멀티쓰레드에서 한 쓰레드는 epoll_wait 하고 있고 다른 스레드에서 epoll_ctl을 수행해 epfd에 add할 경우, **//
//**  새로 추가된 fd가 바로 적용된다. epoll_wait는 새로 추가된 fd의 준비 여부를 리턴 결과에 포함 한다. **//


비트
설명
EPOLLIN
높은 우선순위 데이터 외의 데이터를 읽을 수 있다.
EPOLLPRI
높은 우선순위 데이터를 읽을 수 있다
EPOLLRDHUP상대편 소켓 셧다운
EPOLLOUT일반 데이터를 기록 할 수 있다
EPOLLET 에지 트리거 이벤트 통지를 적용
EPOLLONESHOT
 이벤트 통지 뒤에 감시를 비활성화 한다.
EPOLLERR에러 발생
EPOLLHUP장애 발생 (hangup)



하늘색은 EPOLL_CTL의 입력, WAIT 리턴 둘다 사용
주황색은 CTL의 입력에서만 사용
회색은 WAIT 리턴에서만 사용

EPOLLONESHOT
기본적으론 epoll_ctl로 관심목록에 추가하면 제거할때까지 활성 상태로 남게 된다.
특정 fd로부터 통지를 받으려면 ev.ents값에 EPOLLONESHOT 를 지정하면 됨. 지정하고 wait를 호출하며 해당 fd가 ready상태인지 알려준뒤 해당 fd를 비활성화가 되고 이후에 다시 wait를 호출하면 비활성화된 fd는 안알려준다. (필요할 경우 EPOLL_CTL_MOD 를 사용해 재활성화 해야 함. )


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include "sys/epoll.h"
void epoll( const char* pName )
{
    int epCnt = 10;
    epfd = epoll_create( epCnt );
    if ( -1 == epfd ) return;
    for ( int i = 0; i < 5; ++i ) {
        int fd = open( pName, O_RDONLY );
        if ( -1 == fd ) return;
        printf("Opened : %s, fd %d\n", pName, fd );
        struct epoll_event event;
        event.events =  EPOLLIN;
        ev.data.fd = fd;
        if ( -1 == epoll_ctl( epfd, EPOLL_CTL_ADD, fd, &event ) )
            return;
        while ( epCnt - 1 > 0 ) {
            printf("About to epoll_wait\n");
            // 한번에 처리 가능한 이벤트 갯수
            const int MAX_EVENTS = 5;
            struct epoll_event eventList[ MAX_EVENTS ];
            int ready = epoll_wait( epfd, MAX_EVENTS, -1 );
            if ( -1 == ready ) {
                if ( EINTR == errno )
                    continue; // 시그널에 의해 중단되면 실행 재개
                else
                    return; // 준비된 fd 없음..
            }
            printf("Ready : %d\n", ready );
            for ( int eventIndex = 0; eventIndex < ready; ++eventIndex ) {
                printf("fd %d, EPOLLIN? %s, EPOLLHUP? %s, EPOLLERR? %s\n",
                    eventList[ eventIndex ].data.fd,
                    eventList[ eventIndex ].events & EPOLLIN ? "true" : "false",
                    eventList[ eventIndex ].events & EPOLLHUP ? "true" : "false",
                    eventList[ eventIndex ].events & EPOLLERR ? "true" : "false"
                    );
            }
            if ( eventList[ eventIndex ].events & EPOLLIN ) {
                int s = read( eventList[ eventIndex ].data.fd, buf, 1024 );
                if ( -1 == s ) return; // 읽기 에러
                printf("reaad %d bytes : %s\n", s, buf );
            }
            else
            {
                printf("closing fd %d\n", eventList[ eventIndex ].data.fd );
                if ( -1 == close( eventList[ eventIndex ].data.fd ))
                    return;
                --epCnt;
            }
        }
    }
    printf("All file descriptors closed; bye\n");
}


댓글

이 블로그의 인기 게시물

UNIX C errno 정리( 에러 번호 )

#define EPERM   1   /* Operation not permitted      */ #define ENOENT  2   /* No such file or directory        */ #define ESRCH   3   /* No such process          */ #define EINTR   4   /* interrupted system call      */ #define EIO 5   /* I/O error                */ #define ENXIO   6   /* No such device or address        */ #define E2BIG   7   /* Arg list too long            */ #define ENOEXEC 8   /* Exec format error            */ #define EBADF   9   /* Bad file descriptor          */ #define ECHILD  10  /* No child processes           */ #define EAGAIN  11  /* Resource temporarily unavailable */ #define ENOMEM  12  /* Not enough space         */ #define EACCES  13  /* Permission denied            */ #define EFAULT  14  /* Bad address              */ #define ENOTBLK 15  /* Block device required        */ #define EBUSY   16  /* Resource busy            */ #define EEXIST  17  /* File exists              */ #define EXDEV   18  /* Improper link            */ #define ENODEV  19  /* No such

Baud Rate 와 Bit Rate 의 차이점

출처 - http://solvline.com/technical_info/tech_note_view.php?no=22&fno=&PHPSESSID=f5f096a5b1090ca017552de78745b8aa 1. Bit Rate 와 Baud Rate 의 정의 1.1 Bit Rate 정의 비트 레이트 (Bit Rate) 는 초당 얼마나 많은 데이터 비트 (‘1’ 또는 ‘ 0’) 를 전송할 수 있는가를 나타내는 말이다 . 또 우리가 자주 쓰는 BPS 라는 말이 있는데 이는 Bit Per Second 로서 초당 보낼 수 있는 비트의 수를 나타낸다 . 이는 모뎀의 전송속도를 측정하는 단위로 사용되어 졌다 . 일반적으로 28,800 모뎀이라면 28,800bps 의 전송속도를 나타내는 것이다 . 예를 들어 , 2400bit/second(bps) 라면 초당 2400 개의 비트 정보를 전달할 수 있다는 뜻이다 . 이는 반대로 이야기하면 1 비트 정보를 보내기 위해서 416.6us 의 시간 (1s/2400bit) 이 필요하다는 이야기이다 . 1.2 Baud Rate 보 레이트 (Baud Rate) 는 초당 얼마나 많은 심볼 (Symbol, 의미 있는 데이터 묶음 ) 을 전송할 수 있는가를 나타내는 말이다 . 이는 이론적인 통신 단위로 초당 신호 (Signal) 요소의 수 를 나타낸다 . 만약 하나의 신호요소가 2 비트로 구성되어 있는 경우라면 보는 BPS 의 반이 된다 . 즉 , 1 보 동안 2 비트가 전송된다 . 일반적으로 신호를 1 비트로 여긴다면 BPS 와 같은 단위가 된다 . 심볼이란 말은 의미 있는 데이터 비트의 묶음이다 . 일반적으로 시리얼 통신에서는 데이터 비트가 8-bit 를 사용하므로 이를 하나의 심볼이라고 이야기 할 수 있다 . 1 개의 symbol ( 또는 character) 는 8 개의 bit 정보와 같다 . 예를 들어 , 2400 baud rate 를 갖는다는 말은 1 초에 2400 개의

[C언어] epoll 설명

출처 -  http://biscuit.cafe24.com/moniwiki/wiki.php/epoll 1  준비 2  socket 프로그래밍 기본 3  비동기 입출력 (Asyncronous I/O) & 입출력 다중화 (I/O Multiplexing) 4  select 5  select 와  poll  그리고 epoll. 그 차이 6  epoll 프로그래밍 흐름 7  epoll 함수들 8  epoll References 빈폴도 아니고, 이폴이란 대체 무엇일까? 당신은 서버한대로 몇 명의 동시접속자를 수용할 수 있습니까? 최근에 인터넷에 떠돌아다니는  c10k_problem 은 대당 10K, 즉 1만명의 동시접속(concurrent users)을 받아보자는 문제다. 서버 프로그래밍을 해 본 사람이라면 이게 그리 만만한 문제가 아니라는 것을 직감할 듯 --; 요즘의 Massive 온라인게임은 '분산처리'가 기본이라 한 대에서 많은 이용자를 커버하기보다는 여러대가 하나의 세트로써 구성하는 것이 인기가 있고 다수의 커넥션보다는 소수 커넥션에서의 대용량 전송이 더 중요한 요소이기도 하다. c10k problem에 나또한 관심을 가지게 되었고, epoll 이 최근 급부상하는 솔루션으로 인기가 있다기에 한 번 파보자 하고 결심하고 이 글을 시작했다. 마침 wiki에도 관심이 있던 차라, wiki 공부도 할 겸해서 epoll 을 연구하는 과정을 이 wiki에 담아 보고자 한다. 1  준비  # * 누구를 위한 epoll 인가? epoll은 '한 대의 서버에서 아주많은 동시접속자를 처리하기 위한 수단'이다. 이미 당신이 그 수단을 알고 있다면 - epoll 이건 아니건 - 이 글은 별로 도움이 안될듯하다. 동시접속자가 천명을 넘지않는다면 구닥다리 방법을 이용하는 것과 큰 차이가 없으리라 본다. 또한, epoll은  Linux 프로그래머의 도구 이다. M$ wind