2014년 12월 19일 금요일

TCP/IP 소켓 프로그래밍 12강

IO 멀티플렉싱에 대해서 알아볼려고 한다.

12-1 IO멀티플렉싱 기반의 서버

멀티프로세스 서버는 단점이 있었다. 다중 접속 서버의 구현을 위해서는 클라이언트가 연결요청이 있을 때마다 새로운 프로세스를 생성했다.
적은 접속에는 무리가 없지만 많은 클라이언트들의 연결요청이 있으면 서버에 과부하를 초래한다. 이 과부하를 줄이기 위한 대안이 IO멀티플렉싱이다.

멀티플렉싱이란? 하나의 통신채널을 통해서 둘 이상의 데이터를 전송하는데 사용되는 기술

더 쉽게 말하자면 한개의 프로세스로 여러개의 소겟을 생성해서 동시 접속을 한다는 것이다.
물론 무한정 막 동시 접속을 하진 못한다. 그래서 요청이 오면 요청 순서대로 빠르게 왔다 갔다 하면서 대응하는 것이다. 이것을 도와주는 함수가 select 함수다.

12-2 : select 함수의 이해와 서버의 구현

select 함수를 이용하면 한 곳에 여러 개의 파일 디스크립터를 모아놓고 동시에 이들을 관찰할 수 있다. (관찰 항목 각각을 이벤트라고 부른다)

이 함수의 호출 과정을 보자

파일 디스크립터의 설정, 검사의 범위 지정, 타임아웃 설정 -> select 함수의 호출 -> 호출결과 확인

1)파일 디스크립터의 설정

먼저 관찰하고자 하는 파일 디스크립터를 모아야 한다.
모을 때 (수신,전송,예외)에 따라서 구분해서 모아야 한다.
이때 사용되는 것이 fd_set형 변수다.

이 변수에 들어가는 매크로 함수는 다음과 같다

-FD_ZERO(fd_set* fdset) 모든 비트를 0으로 초기화
-FD_SET(int fd, fd_set *fdset) 파일 디스크립터 정보를 등록
-FD_CLR(int fd, fd_set *fdset) 파일 디스크립터 정보를 삭제
-FD_ISSET(int fd, fd_set *fdset) 호출 결과를 확인하는 용도

2)검사(관찰)의 범위 지정과 타임아웃의 설정

select 함수를 보자. (매개 변수가 좀 많다)

#include <sys/select.h>
#include <sys/time.h>
int select(int maxfd, fd_set *readset, fd_set *writeset,
                           fd_set *exceptset, const struct timeval *timeout);

-maxfd : 검사 대상이 되는 파일 디스크립터의 수
-readset : fd_set형 변수에 수신된 데이터 존재여부에 관심 있는 파일 디스크립터 정보를 모두 등록해서 그 변수의 주소 값을 전달한다.
-writeset : fd_set형 변수에 블로킹 없는 데이터 전송의 가능여부에 관심있는 파일 디스크립터 정보를 모두 등록해서 그 변수의 주소값을 전달한다.
-exceptset : fd_set형 변수에 예외상황의 발생여부에 관심이 있는 파일 디스크립터 정보를 모두 등록해서 그 변수의 주소 값을 전달한다
-timeout : select 함수 호출 이후에 무한정 블로킹 상태에 빠지지 않도록 타임아웃을 설정하기 위한 인자를 전달한다

반환 값 : 오류발생시에는 -1이 반환되고, 타임 아웃에 의한 반환시에는 0이 반환된다. 그리고 관심대상으로 등록된 파일 디스크립터에 해당 관심에 관련된 변화가 발생하면 0보다 큰 값이 반환되는데, 이 값은 변화가 발생한 파일 디스크립터의 수를 의미한다.

이 함수를 호출에 앞서 결정해야 할 것이 2가지 있다.
-파일 디스크립터의 관찰 범위는 얼마인지
-select 함수의 타임아웃 시간을 어떻게 해야하나

예제를 보자.

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>

#define BUF_SIZE 30

int main(int argc, char *argv[])
{
fd_set reads, temps;
int result, str_len;
char buf[BUF_SIZE];
struct timeval timeout;
//fd_set형 변수를 초기화 한다.
FD_ZERO(&reads);
//파일 디스크립터 0의 위치를 1로 설정해 준다.
FD_SET(0, &reads); // 0 is standard input(console)

/* //1번만 초기화하면 문제가 생기기에 주석 처리 했다.
timeout.tv_sec=5;
timeout.tv_usec=5000;
*/

while(1)
{
temps=reads; //원본을 유지하기 위해 복사한다.
//select 함수 실행전에 반복 초기화 시켜준다.
timeout.tv_sec=5;
timeout.tv_usec=0;
//데이터에 변화가 있으면 변화된 갯수를 를 반환한다, 데이터 변화가 없으면 0을 반환한다.
result=select(1, &temps, 0, 0, &timeout);
if(result==-1)
{
puts("select() error!");
break;
}
else if(result==0)
{
puts("Time-out!");
}
else //데이터 변화가 있을 경우
{
if(FD_ISSET(0, &temps))  //표준 입력이 맞다면
{
str_len=read(0, buf, BUF_SIZE);
buf[str_len]=0;
printf("message from console: %s", buf);
}
}
}
return 0;
}

이 역시 소스를 다운 받아서 해봐야 더 수월하게 알 수 있다.
물론 책도 구입해서 공부하는 것이 제일 좋다;;;
현재 보고 있는 책은 "윤성우 열혈 TCP/IP 소켓 플로그래밍"이다
소스 다운 받기

13강에는 다양한 입출력 함수들에 대해 알아보겠다.

댓글 없음:

댓글 쓰기