기본 콘텐츠로 건너뛰기

[C언어] select / poll / epoll example

* select()

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int n,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
FD_SET(int fd, fd_set *set); // fd를 set(검사대상)에 추가
FD_CLR(int fd, fd_set *set); // fd를 set에서 제거
FD_ZERO(fd_set *set);// set에 지정된 모든 대상 제거,select호출 전 항상 호출함
FD_ISSET(int fd, fd_set *set); //select()호출 후 fd가 사용 가능한지 확인 return bool

ex)
struct timeval tv;
fd_set readfds;
int ret;

FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);

tv.tv_sec = 0;
tv.tv_use = 500;
ret = select (STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);

if(FD_ISSET(STDIN_FILENO, &readfds)){ /* 'fd' is readable without blocking! */ }

* poll()

#include <sys/poll.h>

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};

ex)

struct pollfd fds[2];
int ret;

fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;

fds[1].fd = STDOUT_FILENO;
fds[1].events = POLLOUT;

ret = poll(fds, 2, TIMEOUT);

if(fds[0].revents & POLLIN){ /* stdin is readable */ }
if(fds[0].revents & POLLOUT){ /* stdout is writable */ }

poll() vs select()

poll  select 

매개변수에 +1(FILENO+1)이 필요없다   

fd의 숫자가 큰 경우 select보다 효율적  fd_set값이 크면 비효율적이다. 
bitmask를 모두 검사하며 특히 bit가 분산된 경우 더욱 비효율적이다 
매번 set을 초기화해야 한다.(FD_ZERO)
이식성을 높이기 위해 timeout parameter(timeval)를 매번 초기화 해야함

몇몇 UNIX에서는 poll을 지원하지 않는다 이식성이 높다
    microsecond단위까지는 timeout resolution이 더 좋다

*epoll()

Epoll(Event Poll): poll()과 select()를 개선한 형태

2.6 Linux kernel 이후부터 사용 가능
select()/poll()은 호출될 때마다 fdset을 모두 확인하나 epoll은 실제 감시작업과 감시 등록작업을 분리하는 방법으로 이런 문제를 해결.

#include <sys/epoll.h>

int epoll_create(int size)

// size는 감시대상의 개수를 알려주는 힌트이며 정확한 수를 요구하지는 않는다.
// return value : file descriptor or error(-1)
// file descriptor는 poll이 끝난 다음 close()를 이용하여 닫아야 한다.

ex)
int epfd;

epfd = epoll_create(100);
if(epfd < 0) // errorclose(epfd);
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
struct epoll_event{
__u32 events; /* events */
union {
void *ptr;
int fd;
__u32 u32;
--u64 u64;
}data;
};

// op parameter
// EPOLL_CTL_ADD : 감시대상에 fd 추가
// EPOLL_CTL_DEL : 감시대상에서 fd 제거
// EPOLL_CTL_MOD : 기존 등록된 fd의 event를 수정

ex)

struct epoll_event event;
int ret;

event.data.fd = fd;
event.events = EPOLLIN | EPOLLOUT;

ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
if(ret) //ERROR
event.data.fd = fd;
event.events = EPOLLIN;
ret = epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);
ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event);

** EPOLL_CTL_DEL을 사용할 때 event를 NULL로 보내면 2.6.9이전 버전에서 호환성이 맞지 않는다.
event 매개변수의 events필드에 EPOLLET값을 설정하면, fd에 대한 감시가 레벨트리거에서 에지트리거로 바뀐다. 에지트리거는 일반적으로 비차단 입출력을 활용하도록 다른 프로그래밍 접근방식을 요구하므로(만약 read를 요청하는 시점에 읽을 수 있는 상태라고 해도 write가 진행중이면 write가 끝날 때까지 기다린다) EAGAIN을 주의깊게 검사해야 한다.

#include <sys/epoll.h>

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

ex)

#define MAX_EVENTS64

struct epoll_event *events;
int nr_events, i, epfd;

events = malloc (sizeof(struct epoll_event) * MAX_EVENTS);

nr_events = epoll_wait (epfd, events, MAX_EVENTS, -1);

if(nr_events < 0) 
{
free(events);
return 1; //ERROR
}
for(i =0; i < nr_events; I++) 
{
//events[i].events마다 events[i].data.fd에 대한 작업 진행가능
}
free(events);



댓글

이 블로그의 인기 게시물

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   ...

I,P,B 프레임

출처 -  http://microdev.tistory.com/116 정화상으로 압축된 프레임을 I 프레임, 예측만을 한 프레임을 P 프레임, 보간을 한 프레임을 B 프레임이라 한다.  엠펙 비디오는 이들 세 종류의 프레임들이 일정한 패턴으로 섞인 것이다. I-프레임(Intra-coded frame) 데이타 스트림의 어느 위치에도 올 수 있으며, 데이타의 임의 접근을 위해 사용되며, 다른 이미지들의 참조 없이 부호화된다. I-프레임은 정화상 압축방법(JPEG)을 이용하지만, JPEG과는 달리 MPEG에서는 실시간으로 압축이 이루어진다. I-프레임의 압축은 MPEG에서는 가장 낮은 압출률을 보인다 I-프레임은 매크로 블럭내에서 지정된 8*8 블럭으로 나눈 후, DCT 기법을 사용한 후, DC계수는  DPCM 방법으로 부호화하는데, 연속한 블럭 사이의 차이값을 계산한 후 가변 길이 코딩을 사용하여 변환한다. . P-프레임(Predictive-coded frame) 부호화와 복호화를 행할 때 이전의 I-프레임 정보와 이전의 P-프레임의 정보를 사용한다. P-프레임은 연속되는 이미지들의 전체 이미지가 바뀌는 것이 아니라 이미지의 블럭들이 옆으로 이동한다는 점에 착안한 것이다. 즉, 움직임이 있는 경우 앞화면에 있는 물체 자체의 모양에는 큰 변화없이 옆으로 이동하는 경우가 대부분이므로, 이전의 화면과 현재의 화면의 차이가 매우 적은 것을 이용하여 차이값만을 부호화하는 것이다. B-프레임(Bidirectional-coded frame) 부호화와 복호화를 행할 때 이전, 이후의 I-프레임과 P-프레임 모두를 사용한다. B-프레임을 사용하면 높은 압축률을 얻을 수 있다. B-프레임은 이전의 I-또는 P-프레임과 B-프레임 이후의 I-또는 P-프레임의 차이값을 가진다. I-프레임으로 시작하는 연속적인 화상들의 집합을 GOP(Group Of Picture)라고 한다. 아래그림은 화상들의 GOP를 나타내는 것이다. B-프...

시리얼(Serial) 이란?

출처 - http://www.ni.com/white-paper/2895/ko/#toc4 시리얼은 거의 모든 PC에서 표준으로 사용되는 디바이스 통신 프로토콜입니다. 시리얼의 개념을 USB의 개념과 잘 구분하십시오. 대부분의 컴퓨터에는 2개의 RS232 기반 시리얼 포트가 있습니다. 시리얼은 또한 여러가지 디바이스에서 계측을 위한 일반 통신 프로토콜이며, 여러 GPIB 호환 디바이스에는 RS232 포트가 장착되어 있습니다. 뿐만 아니라, 원격 샘플링 디바이스로 데이터 수집을 하는 경우에도 시리얼 통신을 사용할 수 있습니다. 시리얼 통신의 개념은 간단합니다. 시리얼 포트는 정보의 바이트를 한번에 한 비트씩 순차적으로 송수신합니다. 한번에 전체 바이트를 동시에 전달하는 병렬 통신과 비교하면 시리얼 통신은 속도가 느리지만 훨씬 간단하며 장거리에도 사용할 수 있습니다. 예를 들어, 병렬 통신용 IEEE 488 스펙을 보면 기기간 케이블링은 총 20 m 미만이어야 하며, 두 개의 디바이스간은 2 m 미만이어야 합니다. 반면 시리얼 통신은 최대 1.2 Km의 통신거리를 보장합니다. 통상 엔지니어들은 ASCII 데이터를 전송할 때 시리얼 통신을 사용합니다. 이 때 송신용 (Tx), 수신용 (Rx), 그라운드용 (GND)의 세 가지의 전송 라인을 사용하여 통신합니다. 시리얼은 비동기식이므로 포트는 한 라인에서 데이터를 전송하고 다른 라인에서 데이터를 수신합니다. 핸드쉐이킹용 라인도 사용 가능하지만 필수 요구사항은 아닙니다. 시리얼 통신의 가장 중요한 특징에는 보드 속도 (baud rate), 데이터 비트, 정지 비트, 패리티가 있습니다. 두 개의 포트가 통신하기 위해서는 이러한 파라미터가 반드시 적절하게 맞춰져야 합니다. 보드 속도는 통신의 속도를 측정하는 수치이며 초당 비트 전송 숫자로 표시됩니다. 예를 들어 300 보드 속도는 초당 300 비트를 의미합니다. 엔지니어들이 흔히 말하는 클럭 주기는 보드 속도를 의미합니다. 따라서 프로토콜에 ...