IO 멀티플렉싱

b4failrise ㅣ 2018. 11. 13. 23:10

멀티플렉싱 서버의 구현에 있어서 가장 대표적인 방법 : select()


select함수를 사용하면 한곳에 여러 개의 file descriptor를 모아놓고 동시에 이들을 관찰할 수 있다.

*파일 디스크립터의 관찰은 소켓의 관찰로 해석할 수 있다.

파일 디스크립터에 대한 관찰을 하는 데 사용되는 것이 fd_set형 변수이다. 이는 0과 1로 표현되는, 비트단위로 이뤄진 배열이다.

이러한 자료형으로 각 file descriptor에 대해 세 가지에 대해서 관찰을 한다.

- read buffer 관련

- write buffer 관련

- exception 관련


이러한 관찰범위를 select 함수에 fd_set 변수를 선언하여 변수의 주소값을 넘겨준다.

관심없는 관찰에 대해선 NULL을 넘겨주면된다.


select의 parameter를 살펴보면 다음과 같다.



readfds 는 read buffer 즉, '수신된 데이터의 존재여부'에 관심 있는 file descriptor 정보를 모두 등록해서 그 변수의 주소 값을 전달한다.

writefds 는 write buffer 즉, '블로킹 없는 데이터 전송의 가능여부'에 관심 있는 file descriptor 정보를 모두 등록해서 그 변수의 주소 값을 전달한다.

exceptfds는 exception 즉, ' 예외상황의 발생여부'에 관심있는 파일 디스크립터 정보를 모두 등록해서 그 변수의 주소 값을 전달한다.


※readfds, writefds, exceptfds는 모두 서로 다른 fd_set 형 변수이다.



관찰 대상이되는 파일 디스크립터의 수를 나타내는 nfds에 대해서 알아보자.

여기서 주의해야할 것은 관찰 대상이 되는 file descriptor의 정확한 개수를 넘기는 게 아니라

'가장 큰 file descriptor의 값 + 1' 을 select의 가장 첫번째 인수로 넘겨준다는 것이다.

이 의미는 fd_set형 배열을 nfds만큼 순회하면서 값이 1인 file descriptor를 캐치한다는 것이다.


Q. 관찰을 원하지 않는 file descriptor의 변화를 감지할 수 있지 않은가?

우리는 fd_set형 변수에서 관심있는 file descriptor를 1로 set한다. 그리고 이 fd_set 변수는 초기화하는 데 사용되고

이 변수를 또다른 fd_set형 변수를 선언하여 복사해준다. 

그래서 매번 select 하기 전에 원래의 fd_set(1)으로 초기화한다. 그 다음, select의 fd_set 자리에는 복사한 fd_set(2)형 변수의 주소값을 넘겨준다.

select는 fd_set의 1로 셋팅된 것으로 관찰 대상인 file descriptor를 판별하는데 매번 초기화를 안 해주면 들어갈 때마다 값이 바뀌기 때문에 관찰대상이 계속 바뀌어 의미가 없어진다.



Select함수는 변화를 감지하기 위한 목적이 있다. 그래서 세 가지 관찰범위에 대해서 변화가 일어나지 않으면 반환을 하지 않는다. 이러한 infinite blocking 상태에 빠지지 않게 하기 위해서 설정한 timeout 시간을 초과하면 0을 반환하도록 한다.


실패하면 -1을 반환하고 성공 시, 변화가 일어난 file descriptor의 수를 반환한다.