컴퓨터 공부/네트워크 프로그래밍

[TCP/IP 소켓 프로그래밍] 12. 프로세스간 통신(IPC)

려리군 2009. 7. 30. 11:04

12-1. I/O 멀티플렉싱 기반의 서버

하나의 전송로를 여러 사용자가 동시에 사용해서 효율성을 극대화 하는 것. 전송로를 공유.

전송로를 공유하기 위해서는 서로 약속이 필요하다.

TDMA : 자료 전송 시간을 일정한 시간 폭으로 나누어서 함께 공유하는 방식

FDMA : 주파수 대역 폭을 나누어서 함께 공유하는 방식


I/O 멀티플렉싱

클라이언트와의 입/출력을 담당하는 프로세스를 하나로 묶어버리는 것.

프로세스 = 고속의 전송로.


multitasking(멀티태스킹) 예시


multiplexing(멀티플렉싱) 예시

※ 데이터 입출력 및 접속 모두를 하나로 묶어서 처리한다.

※ 멀티플렉싱 서버가 멀티태스킹 서버보다 성능이 좋다. -> context switching이 없음.


멀티 프로세스 vs 멀티 플렉싱

멀티 프로세스

클라이언트와 서버간의 송수신 데이터 용량이 큰 경우.

송수신이 연속적으로 발생하는 경우에 적합.

멀티 플렉싱

클라이언트와 서버간의 송수신 데이터 용량이 작은 경우.

송수신이 연속적이지 않은 경우에 적합. (예: 채팅)

멀티 프로세스 기반의 서버에 비해 많은 수의 클라이언트 처리에 접함.


12-2. Select 함수 사용하기

파일 디스크립터의 설정

지정된 파일 디스크립터의 변화를 확인한다.

파일 디스크립터 변화 : 파일 디스크립터를 통해 데이터 송수신이 가능한 상태

예시)


1. 파일 디스크립터 설정

관찰하고자 하는 파일 디스크립터를 모아놓는다. (총 3묶음)

2. 파일 디스크립터의 변화(3가지 종류 존재)

입력 버퍼의 변화 : 수신할 데이터가 존재하는가? (입력 버퍼에 데이터 존재)

출력 버퍼의 변화 : 데이터 전송이 가능한 상태인가? (출력 버퍼에 충분한 여유공간 존재)

예외(OOB)상황 관련 버퍼의 변화 : 소켓에서 예외상황이 발생 하였는가?

3. fd_set 자료형

파일 디스크립터를 구분 지어 모아두기 위한 자료형(비트단위 배열)


파일 디스크립터 검사 범위 설정
매크로 함수

FD_ISSET(int fd, fd_set *fdset);
fdset에서 해당 fd(번호)의 비트가 1인지 확인한다. 1이면 TRUE, 0이면 FALSE.

검사해야 할 파일 디스크립터의 개수(범위)를 지정해 준다.

(select 마지막에 리턴된 디스크립터 값에) 가장 큰 파일 디스크립터 값에 1을 더해서 인자를 전달.


Timeout(타임아웃) 설정

Timeout : 정해 놓은 시간이 지나면 (select)함수가 리턴하게 한다.
struct timeval
{
    long tv_sec;    // 초단위
    long tv_usec;  // 마이크로초단위 1/10^6
};

select함수
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>

int select(int n, fd_set * readfds, fd_set *writefds, fd_set * exceptfds,struct timeval * timeout);
리턴 : 오류 발생이면 -1, 타임아웃이면 0, 변화가 발생하면 0이 상에 상태가 바뀐 파일 디스크립터 수.
n : 파일 디스크립터 개수(범위) 지정.
readfds : 입력버퍼(수신)할 데이터가 있는지 검사.
writefds : 출력버퍼가 충분히 여유가 있는지 검사.
exceptfds : OOB에 대한 검사. ※ 추후설명
timeout : 타임아웃 설정관련 인수.


select함수를 호출하기 전에는 fd_set에 검사하기 원하는 index의 비트1로 세팅해 놓는다.
예시) FD_SET(0, &read_s);    // standard input에 대한 디스크립터를 1로 세팅.
select함수가 리턴이 되면 fd_set에 검사한 결과에 대한 index의 비트만이 1로 세팅되어 있을 것이다.
※ select함수 호출 전과 호출 후에 값이 바뀌기 때문에 select함수를 호출할 때마다 초기화할 수 있도록 원본 fd_set을 복사하여 사용한다.
※ timeout도 select함수 호출 전과 호출 후에 값이 바뀌기 때문에 루프 시작할 때 값을 새로 초기화 주는 것이 좋다.

12-3. 멀티플렉싱 서버의 구현
FD_SET(serv_sock, &reads);
※ 서버소켓으로 오는 입력버퍼(데이터)의 내용이 중요하다. 그 내용은 클라이언트로부터 들어오는 연결요청(일종의 데이터이기 때문)이다.
fd_max : 검사할 디스크립터 개수(범위)를 저장하기 위한 값. 0~fd_max+1의 범위로 설정한다.

12-4. 윈도우즈 기반으로 구현하기
select 함수와 timeval 구조체는 선언된 형태와 기능이 리눅스와 같다.
int select(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);

※ fd_set 자료형은 기능이 리눅스와 같지만 선언형태는 다르다.
typedef struct fd_set{
    u_int fd_count;                                 // 얼마나 많이 설정되어 있는가?
    SOCKET fd_array[FD_SETSIZE];      // SOCKET의 배열
}fd_set;
※ 소켓의 핸들 값이 일정하지 않고 윈도우즈에는 리턴된 핸들 값을 기억하는 것이 편하다.
그러므로 소켓 핸들의 개수를 fd_set 내부적으로 보관하고 있다.


※ 다음 매크로는 리눅스와 사용 방법은 거의 같다.
FD_CLR(s, *set)
:set 포인터가 가리키는 배열에서 핸들 s를 삭제한다.
FD_ISSET(s, *set)
:핸들 s가 set포인터가 가리키는 배열의 멤버라면 TRUE를 아니면 FALSE를 리턴한다.
FD_SET(s, *set)
:핸들 s를 set포인터가 가리키는 배열의 멤버에 포함시킨다.
FD_ZERO(*set)
:set 포인터가 가리키는 배열을 0으로 초기화한다. 

select(0, &temps, 0, 0, &timeout)
※ 윈도우즈 기반에서는 nfds인수가 필요없다.