반응형

poll(2)

#include <poll.h>

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

poll(2)함수는 select(2)함수와 비슷한 기능을 하는 함수로 socket / pipe 등에서 동시에 여러개의 I/O를 대기할 경우에 특정한 fd에 blocking되지 않고 I/O를 할 수 있는 상태인 지를 모니터링하여 I/O 가능한 상태의 fd인지를 검사하는 함수입니다. 

poll(2)함수는 일반파일에서는 사용할 일은 거의 없으며, 주로 socket통신이나 pipe등에서 사용합니다.

통신에서 데이터를 read(2) 또는 recv(2) 할 때, peer(상대쪽)에서 데이터 전송을 하지 않았는 데, read / recv 함수를 호출하면 데이터가 수신될 때까지 block 상태가 됩니다. 

 그런데, 만약 하나의 프로그램에서 여러개의 socket/pipe에서 데이터 읽기를 해야하는 경우에는 어느 fd에서 데이터가 먼저 올지 아무도 모르기 때문에 fd를 순서대로 읽기를 시도한다면 첫번째 fd에 상대방이 데이터 전송을 하지 않게 되면 나머지 fd에 대해서는 상대가 데이터를 전송했는 데도 불구하고 처리를 하지 못하는 문제가 발생합니다.

poll(2)함수는 여러개의 fd를 동시에 모니터링하다가 한개라도 읽을(주로 읽을 때에 문제가 됨) 수 있는 상태가 되면 blocking을 해제합니다. read/recv에 대한 timeout도 설정할 수 있어서 특정시간이 지나도 읽을 수 없으면 오류처리하거나 다른 작업을 할 수 있습니다. select(2)는 readfds/writefds/execptfds등을 재활용할 수 없지만, poll은 struct pollfd의 값을 한번 설정하면 fd가 추가되거나 삭제되지 않으면 다시 설정할 필요없습니다.

 

 

파라미터

fds
    - 모니터링할 fd와 event  종류를 설정하고 poll이 반환되었을 때에 그 결과값을 저장하는 구조체입니다.

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

  fd : file descriptor
  events : monitoring할 event 종류로 아래의 상수로 Bit Or 연산으로 여러가지 설정할 수 있습니다.
  revents : 반환 event로 events에서 설정한 값 중에 일치하는 값과 추가적인 몇가지 event가 설정됩니다.
  [Event 상수 값]
   POLLIN : 읽을 데이터가 있습니다.  (events / revents)
   POLLPRI : 긴급 데이터(Out-of-band Data)를 읽을 것이 있습니다. (events / revents)
   POLLOUT : 바로 쓸 수 있는 상태입니다. (events / revents)
   POLLWRBAND : 긴급 데이터(Out-of-band data)를 쓸 수 있습니다. (events / revents);
   POLLERR : 주어진 file descriptor에 오류가 있습니다. (revents only)
   POLLHUP : 주어진 file descriptor에서 event가 지체되고 있습니다. (revents only)
   POLLNVAL : 주어진 file descriptor가 유효하지 않습니다. (revents only)
nfds
    - 설정된 fds의 개수
timeout
    - milliseconds(1/1000초) 단위의 timeout을 설정합니다.
    - 0을 설정하면 poll(2)함수는 바로 return 됩니다.
    - -값이면 타임아웃이 무한대로 설정됩니다. 즉, event가 발생할 때까지 무한 대기합니다.

 

RETURN

1 이상
    -  Event가 발생한 fd의 갯수

0
    - timeout이 발생하였습니다.

-1
    - 오류가 발생하였으며, 상세한 오류내용은 errno에 설정됩니다.
    
      EFAULT : fds 변수가 프로그램의 주소  공간에 있지 않습니다.
      EINTR : signal이 발생하였습니다.
      EINVAL : nfds 값이 RLIMIT_NOFILE를 초과하였습니다.
      ENOMEM : file descriptor table 메모리 할당을 위한 공간이 없습니다.

 


활용 예제

 

Sample

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <poll.h>
#include <errno.h>

......

int main(void)
{
    int retval;
    int sock, sock1, sock2;
    int fds;
    char buffer[4096];
    int size;
    struct pollfd fds[100];
    int nfds;
    int idx;

    ......

    if((sock = socket(....)) == -1) {
        return 1;
    }

    if(bind(sock, ....) == -1) {
        return 1;
    }

    ......

    sock1 = accept(...);
    sock2 = accept(...);

    ......

    memset(pollfd, 0x00, sizeof(pollfd));
    fds[0].fd        = sock1;
    fds[0].events    = POLLIN | POLLPRI;
  
    fds[1].fd        = sock2;
    fds[1].events    = POLLIN | POLLPRI;

    nfds = 2;

    /* timeout 5초로 설정함 */
    retval = poll(fds, nfds, 5000);

    if (retval == -1) {
        fprintf(stderr, "select error: %s\n", strerror(errno));
    } else if (retval == 0) {
        fprintf(stderr, "timeout이 발생하였습니다.\n");
    } else {
        for(idx = 0; idx < nfds; idx++) {
            if(fds[idx].revents & (POLLIN | POLLPRI)) {
                if((size = read(sock1, buffer, 4096)) > 0) {
                    buffer[size] = 0x00;
                    printf("SOCK1: %s\n", buffer);
                }
            }
        }
    }

    return 0;
}

 


see also : Socket 통신과 Socket 응용

 

 

 

 

반응형
블로그 이미지

자연&사람

행복한 개발자 programmer since 1995.

,