// 다중 입출력 함수(select(), pselect(), poll(), ppoll())

// 

// 다중 입출력은 여러 fd 를 동시에 차단하면서 fd 중 하나가 차단 없이 읽고 쓸 준비가 될 때 알려주는 기능

// 다중 입출력을 위한 기본 방식

// 1. fd 중 하나가 입출력이 준비될 때를 알려준다.

// 2. 하나 이상의 fd 가 준비될 때까지 잠든다.

// 3. 어떤 fd 가 준비되었는지 확인 후 준비가 되면 깨어난다.

// 4. 차단 없이 모든 fd 가 입출력을 준비하도록 관리한다.

// 5. 1단계로 돌아가서 다시 시작한다.

// 

// select()

// 한 곳에 모아 놓은 여러 file descriptor를 동시에 관찰할 수 있음

// 수신한 데이터를 지니고 있는 file descriptor가 어떤 것들인지,

// 데이터를 전송할 경우 blocking 되지 않고 바로 전달 가능한 file descriptor는 어떤 것들인지,

// 또한 예외가 발생한 file descriptor는 어떤 것들인지 정도가 관찰 내용이 됨

//

// 함수 호출 과정

// descriptor 설정, 검사 범위 설정, time out 설정

// => select 함수 호출

// => 결과 확인

//

// select 함수는 지정된 file descriptor의 변화를 확인함, 

// 즉, file descriptor를 통하여 테이터 송,수신 가능 여부를 체크하는것

// 또한, I/O 버퍼를 생성했다는 것과 같은 말이자,

// file descriptor의 변화는 I/O 버퍼에 변화가 생겼다는말

// 만약 file descriptor에 변화가 생기지 않았다면 변화가 발생할 때까지 select 함수가 돌아가니

// 그 동안에는 blocking에 걸리게 됨, 이점을 해결하기 위해서 time out을 걸어줌

// time out을 설정해 놓으면 그 시간만큼 시간이 지나 return 되기 때문에 bloking 상태를 피할 수 있음

//

// 관찰 항목이 세가지 이므로 file descriptor의 묶음도 세가지로 준비해야함

// file descriptor를 세묶음으로 모아 놓기 위해서 사용되는 것이 fd_set 데이터 타입의 자료형

// fd_set은 0, 1 을 나타내는 배열이라 생각하면 됨

typedef struct fd_set{

u_int fd_count;

SOCKET fd_array[FD_SETSIZE]

} fd_set;


// fd_count : 설정하는 socket 번호.

// fd_array : 설정된 socket 배열.

//

// fd 가 입출력을 수행할 준비가 되거나 정해진 시간이 결과할 때까지 차단


#include <sys/select.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

  int select(int mafdl, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

// 성공 시 반환 값 : 준비된 fd 개수

// 준비된 fd가 있을 때 준비된 fd 갯수를 반환

// fd 집합은 준비된 fd에 해당하는 비트들만 켜진 상태가 됨

// 시간 만료시 반환값 : 0

// 지정된 fd 중 하나가 준비되기 전에 시간이 만료되면 0을 반환

// 이 경우 fd 세 집합 비트들은 모두 0이 됨

// 오류 시 반환 값 : -1

// 지정된 fd 중 하나가 준비되기 전에 신호가 잡혀서 select 호출이 가로채여 -1이 반환

// 이 경우 fd 세 집합의 비트들은 모두 수정되지 않음

// ===========================================================================================================

// timeout : 만료 시간을 담은 구조체

// NULL 로 설정하면 무한정 기다림, fd 중 하나가 준비되거나 신호가 잡힐 때까지 차단

// 0 으로 설정하면 전혀 기다리지 않음, 차단없이 fd 상태만 확인하는 경우에 쓰임

// 0 이 아닌 경우 지정된 sec나 usec 만큼 기다림, fd 중 하나가 준비되거나 시간이 만료되면 반환

// 만약 time out을 설정하지 않을 경우 NULL값을 포인터 인자로 넘겨 주면 됨


#include <sys/time.h>

 

struct timeval {

long tv_sec;  // 초

long tv_usec; // 마이크로 초

};

// ===========================================================================================================

// readfds : 자료 읽기가 준비되었는지 확인할 fd

// 즉, 입력 스트림에 변화가 발생했는지 확인(수신할 데이터가 있는가)

//

// writefds : 자료 쓰기 연산을 끝낼 수 있는지 확인할 fd

// 즉, 데이터 전송시 blocking 되지 않고 바로 전송이 가능한가

//

// exceptfds : 예외가 발생했는지 확인할 fd

// ===========================================================================================================

// fd 집합의 자료 형식은 fd_set으로, fd_set에 fd들을 할당하고 확인하는 방법은 다음의 매크로를 사용해야함

// 즉, fd_set 변수를 조작하는데 사용되는 함수

#include <sys/select.h>

int FD_ISSET(int fd, fd_set *fdset);

// fd 가 집합에 있을 경우의 반환 값 : 0 이 아닌 값

// fd 가 집합에 없을 경우의 반환 값 : 0

void FD_CLR(int fd, fd_set *fdset);

void FD_SET(int fd, fd_set *fdset);

void FD_ZERO(fd_set *fdset);

//

// FD_ZERO  : 주어진 fd_set의 모든 비트를 0으로 초기화, select() 함수를 호출하기 전에 매번 FD_ZERO를 불러야함

// FD_SET   : 집합의 특정 비트를 켤 때 사용, fd 를 집합에서 추가할 때 사용

// FD_CLR   : 집합의 특정 비트를 끌 때 사용, fd 를 집합에서 제거할 때 사용

// FD_ISSET : 특정 비트가 켜져 있는지 확인 할 경우 사용, select() 호출이 반환된 후 fd 가 입출력 준비가 끝났는지 점검하기 위해 쓰임

//

// readfds, writefds, exceptfds 집합에는 감시할 fd 가 없으면 NULL 을 넣을 수 있고,

// 세 집합 모두 NULL 로 하면 sleep 보다 해상도가 높은 타이머를 사용할 수 있게 됨

// sleep 함수는 초 단위 시간만 대기 할 수 있지만 select 함수는 마이크로 초 단위까지 대기할 수 있기 때문

struct timeval tv;

tv.tv_sec = 0;

tv.tv_usec = 500;

select(0, NULL, NULL, NULL, &tv);

// ===========================================================================================================

// mafdl : 점검할 fd의 갯수, fd 집합에서 가장 높은 fd 번호에 1을 더한 값을 넣어줘야함

// 최대 fd 번호에 1을 더하는 이유는 fd 번호가 0부터 시작하기 때문

// <sys/select.h>에 가장 큰 fd 번호로 FD_SETSIZE가 정의되어 있음

// 보통 1024가 정의되어 있는데 이 값은 너무 크므로 최대 fd 번호에 1을 더한 값을 넘겨주는게 좋음

// mafdl 인자가 클수록 select 함수가 감시할 fd가 많아지는 것이기 때문

// ===========================================================================================================

// ex

#include <sys/select.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include <fcntl.h>

#include <stdio.h>

#include <errno.h>

#include <string.h>

#include <signal.h>


#define buf_length 1024


int main()

{

struct timeval tv;

fd_set readfds, tmpfds;

int select_result;

int read_result;

char buf[buf_length + 1];


FD_ZERO(&readfds);

FD_SET(STDIN_FILENO, &readfds);


while(1)

{

tmpfds = readfds;


tv.tv_sec = 3;

tv.tv_usec = 0;


select_result = select(STDIN_FILENO + 1, &tmpfds, NULL, NULL,&tv);


if (select_result == -1)

{

perror("select");

}

else if (select_result == 0)

{

printf("3 sec\n");

}

else

{

if (FD_ISSET(STDIN_FILENO, &readfds)

{

read_result = read(STDIN_FILENO, buf, buf_length);

if (read_result == -1) perror("read"), return(1);

if (read_result) buf[read_result] = '\0', printf("read : %s\n",buf);

if (strncmp(buf, "quit",4) == 0) break;

}

}// end of if

}// end of while

}// end of main

Posted by 뮹실이

최근에 달린 댓글

06-05 08:11
Yesterday
Today
Total