2016년 5월 28일 토요일

뇌자극 TCP_IP 프로그래밍 16강 요약

1. 리눅스 입출력 모델

입출력 모델은 동기, 비동기, 봉쇄, 비봉쇄의 조합이다.
입출력 모델은 입력/출력 모두에 대응되는 모델이지만 서버와 클라이언트 프로그램
모두 입력 함수가 중요하게 다루어지니 read 함수를 기준으로 설명한다.

봉쇄와 비봉쇄, 동기와 비동기

봉쇄 -  프로그램이 특정 영역에서 봉쇄되어서 봉쇄가 풀리기를 기다린다.
비봉쇄 - 기다리지 않으면 비봉쇄다.

동기 - 사건의 시간을 기다리면서 서로 맞추어 알 수 있는 상태, 이것을 동기라고 한다.
비동기 - 사건의 시간을 서로 맞추지 않은 상태다.

동기/봉쇄 입출력 모델

1) 응용 프로그램은 read 함수를 호출한다.
2) 요청을 받은 커널은 데이터를 읽기 위한 초기 작업을 수행한다.
3) 데이터가 준비될 때까지 응용프로그램은 대기한다.
4) 데이터가 들어온다.
5) 커널은 데이터를 유저 영역으로복사하고 read 함수는 반환한다
6) 응용 프로그램은 봉쇄가 풀리고 다음 작업을 수행한다.

장점 - 프로그램 흐름이 명확해서 이해하기 쉽고, 결과 예측과 디버깅이 매우 쉽다.
단점 - 입출력을 기다리는 동안 다른 일을 할 수 없어서 둘 이상의 소켓을 다룰수 없다.

동기/비봉쇄 입출력 모델

비봉쇄 모델에는 비봉쇄 소켓이 필요하다. 비봉쇄 소켓에 read 함수를 호출하면,
커널은 데이터를 읽을 준비만 하고 즉시 반환한다.
fcntl 함수를 이용하면 봉쇄 소켓을 비봉쇄 소켓으로 만들 수 있다.

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, long arg);

-fd : 특성을 제어할 파일 지정 번호
-cmd : 제어에 사용할 명령으로 현재 파일의 설정 값을 가져오거나 설정 값을 변경하는 등의 일을 할 수 있다. 'F_GETFL'로 현재 설정 값을 가져오고, 'F_SETFL'로 현재 설정 값을 변경할 수 있다.
-arg : 변경하기 원하는 설정 값을 지정한다. O_NONBLOCK 으로 비봉쇄로 지정할 수 있다.

비봉쇄 소켓은 데이터가 없어도 즉시 반환하는데, 이때 반환 값이 -1 이다.
-1을 비봉쇄 상태에서 즉시 반환 한 것을 에러라고 인식하면 문제가 되기에 에러 처리를 해줘야 한다.

실제 에러인지, 비봉쇄에 의한 반환인지 확인 방법은 errno 값을 확인 해야 한다.
errno 값이 EAGAIN 또는 EWOULDBLOCK 이면 비봉쇄에 의한 반환이다.
데이터가 없어서 반환 했음을 의미하니 에러로 처리하면 안된다.

#include <errno.h>
extern int errno;

1) read 함수를 호출하면 커널은 데이터를 읽을 준비를 하고 바로 반환한다.
2) 읽을 데이터가 없으면 errno를 EAGAIN 으로 설정하고 -1을 반환한다.
3) 2)를 계속 반환한다.
4) 드디어 파일에 데이터가 입력되었다.
5) read 함수를 호출하면, 커널은 읽은 데이터를 유저 영역으로 복사한다.

장점 - 바쁜 대기 때문에 발생하는 문제는 어느 정도 해결 가능하다.
단점 - 의도하지 않은 지연 시간과 높은 CPU 점유율 때문에 거의 사용하지 않는다.

비동기/봉쇄 입출력 모델

1) 입력 함수를 호출하기 전에 select 함수를 호출한다. 1,2,3 번 소켓의 데이터 입력을 검사하도록 했다.
2) select 함수가 호출되면 1,2,3 번 소켓에 대해서 데이터 입력 초기화를 하고, 데이터 입력을 기다린다.
3) 1번과 2번 소켓에 데이터가 입력되면 반환한다
4) 1)번 소켓에 대해서 read 함수를 호출한다.
5) read 함수는 봉쇄 모드이지만 이미 읽을 데티어가 읽으므로 데이터를 읽어오고 반환한다.
6) 데이터를 처리한다.
7) 4번으로 가서 2번 소켓에 대해서 read 함수를 호출한다.

장점 - 바쁜 대기 상태에 놓이지 않고서도 하나의 프로세스로 여러개의 소켓을 처리 가능
단점 - 모델을 구현한 방식이 문제다(fd_set의 복사와 비트 테이블을 모두 검사 해야 하는 비효율)

비동기/비봉쇄 입출력 모델

1) read 함수를 호출하면 운영체제는 데이터를 읽을 준비를 한다.
2) 데이터를 읽기 위한 초기 작업을 수행한다.
3) 다른 작업을 할 수 있다.
4) 데티어가 준비되면 커널은 이벤트를 발생한다. 리눅스에서는 시그널을 발생한다. (윈도우는 이벤트 객체를 이용한다.)
5) 프로그램이 read 함수를 호출하면 데이터를 커널 모드에서 유저 모드로 복사한다.
6) 시그널 핸들러를 호출해서 데이터를 처리한다.(윈도우눈 콜백 함수를 호출한다.)

리눅스는 epoll가 윈도우는 IOCP가 이 모델을 따른다.

2. 윈도우 입출력 모델

동기/봉쇄 모델

소켓은 기본적으로 동기/봉쇄 모델로 만들어진다. 리눅스와 차이가 없다.

동기/비봉쇄 모델

ioctlsocket 함수로 소켓을 비봉쇄로 만든다.

int ioctlsocket(
  __in SOCKET s,
  __in long cmd,
  __inout u_long *argp
);

s : 설정을 변경할 소켓 핸들이다.
cmd : 소켓의 설정 명령이다.
argp : 소켓의 설정 값으로 cmd의 값을 argp로 변경한다.

소켓을 비봉쇄로 변경하기 위해서는 cmd 매개변수의 FIONBIO를 1로 설정하면 된다.
0으로 하면 봉쇄, 1로 하면 비봉쇄이다.

3. 모델 선택

모델을 선택하기 위해서는 프로그램의 용도와 그에 따른 규모가 결정돼야 한다.

리눅스에서의 일반적인 선택 기준

1) 동접 클라이언트가 많지 않고 연결과 종료가 빈번하지 않은 서비스, 데이터 처리에 시간이 꽤 걸리는 서비스, FTP와 같은 파일 전송 같은 서비스는 동기/봉쇄 모델로 개발한다.

2) 많은 동접 클라이언트가 예상되고, 데이터 처리 시간이 오래 걸리지 않는 서비스라면 비동기/봉쇄 모델의 기술을 사용해서 개발한다.

윈도우에서의 일반적인 선택 기준

1) 많은 수의 클라이언트가 예상되지 않는다면 동기/봉쇄 모델에 멀티 스레드 기술을 응용해서 개발한다.

2) 많은 수의 클라이언트 처리가 예상된다며 Overlapped I/O 와 IOCP를 사용한다.

댓글 없음:

댓글 쓰기