#25 I/O Multiplexing(select) (실습)
select API를 이용해서 inotify fd 와 stdin fd에 대해서 read 이벤트를 감시하고있다가 이벤트가 발생하면 해당 fd에 가서 정보를 읽어오자.
이전에 작성했던 inotify 기능을 작성했던 코드에 stdin fd에대해 읽어오는 부분 + select로 I/O Multiplexing 하는 부분을 붙혀서 코드를 작성 해보자.
1. 이전에 작성했던 inotify.c 파일을 select.c로 카피한다. 아래는 inotify.c 코드이다.
메인함수에서부터 inotify객체를 생성하고 watch를 2개 추가한 뒤, while 루프를 해서 read 를 직접적으로 호출하는 예제였다.
우리는 stdin 에대해서도 I/O multiplexing을 해야하니 코드를 수정해야한다.
stdin의 fd는 파일 실행시 이미 열려있는 상태이다. ( fd : STDIN_FILENO )
2. select API를 추가 해주자.
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
파라미터
- nfds : fdset에 포함된 fd 중 가장 큰 값 +1
- readfds : read가 가능한 시점을 감시하기 위한 fd set, NULL 입력 가능
- writefds : write가 가능한 시점을 감시하기 위한 fd set, NULL 입력 가능
- exceptfds : exception이 가능한 시점을 감시하기 위한 fd set, NULL 입력 가능
- timeout :
- non NULL : 최대 block timeout 값 지정
- NULL : 무한 blocking
우리는 inotify fd 와 STDIN_FILENO fd를 두개를 처리해야한다.
while문 안에있는 read 대신 select API를 호출해주자.
과정
i) nfds : fd > STDIN_FILENO ? fd +1 : STDIN_FILENO +1
(inotify fd 와 STDIN_FILENO fd 둘중 가장 큰값을 찾아내서 +1 해줘야 한다.)
ii)readfds
1. fd_set 변수를 선언한 뒤, FD_ZERO를 이용해서 초기화하고, FD_SET으로 설정 해주자.
2. fd를 fds에 설정한다.
3. STDIN_FILENO를 fds에 설정한다.
4. readfds 에 &fds 를 넣어준다.
iii) writefds : NULL
iv) exceptfds : NULL
v) timeout : struct timeval timeout 변수를 선언하고 설정해준다.
Vi) return value의 반환 값을 참고해 예외처리를 해준다.
ret == -1 : 에러처리
ret == 0 : timeout
ret > 0 : 이벤트 발생
-FD_ISSET 을 이용해서 어느 fd에서 이벤트가 발생한 것인지 찾아준다.
-inotify 에서 이벤트가 발생을때와 STDIN_FILENO에서 발생했을 때 각각의 코드를 짜준다.
Vi) 최종 완성된 select 부분 코드이다.
전체적인 흐름
1. fds 초기화
2. inotify , STDIN_FILENO 설정
3. timeout 5초설정
4. select 함수 설정
5. 예외처리를 하면서 FD_ISSET을 이용해서 i) inotify에서 이벤트일 경우 ii) STDIN 이벤트일경우 두가지에 대해 코드를 작성 해준다.
3. 완성된 전체 코드이다.
4. gcc 컴파일을 해준다.
5. ./select 를 이용해 실행 시켜보자.
기다리니 5초에 한번씩 timeout이 발생한다.
다른 터미널을 열어서 vi select 명령어를 입력하니 정상적으로 반응 하는 것을 알 수 있다!