들어가며
※ 윈도우환경을 기준으로 작성된 글입니다.
Select 함수가 뭘까? select함수는 멀티 플렉싱 서버의 구현에 있어 가장 대표적인 방법이다.
멀티 플렉싱서버란 하나의 프로세스를 통해 여러 개의 클라이언트들과 통신하는 방식의 서버를 말한다.
그럼 어떤 식으로 Select는 하나의 프로세스만으로 여러 클라이언트를 관리할까?
입출력 관찰자 Select
Select 함수는 여러 소켓들을 모아두고 이 소켓들을 관찰할 수 있다. 이때 관찰하는 것은 다음 3가지와 같다.
- 수신 데이터를 지니고 있는 소켓이 존재한가?
- 블로킹되지 않고 데이터의 전송이 가능한 소켓이 존재하는가?
- 예외상황이 발생한 소켓이 존재하는가?
쉽게 말하면, read, write, except 입출력이 발생했는지를 관찰하는 것이다. (수신, 송신, 예외)
Select 함수 호출 과정
Select 함수를 호출하고 활용하는 과정은 세 가지로 나뉜다.
- 소켓, 타임아웃 설정
- select함수 호출
- 호출결과 확인
소켓 설정
select 모델에선 관찰할 소켓들을 fd_set이라는 곳에 모아 관리한다. fd_set은 소켓 배열로 이루어져 있다.
공식 문서 코드
typedef struct fd_set {
u_int fd_count;
SOCKET fd_array[FD_SETSIZE];
} fd_set, FD_SET, *PFD_SET, *LPFD_SET;
이제 입출력을 관찰하고 싶은 소켓을 등록해 주면 된다! fd_set을 관리하는 함수는 4가지가 있다.
- FD_ZERO(set): set을 비운다.
- FD_SET(s, set): 소켓 s를 set에 넣는다.
- FD_CLR(s, set): 소켓 s를 set에서 제거한다.
- FD_ISSET(s, set): 소켓 s가 set에 있는지 체크한다.
이 함수들을 통해 소켓을 등록해준다.
fd_set reads; // read할 socket들의 set
fd_set writes; // write할 socket들의 set
SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, 0);
FD_SET(listenSocket, &reads);
타임 아웃 설정
select는 관찰 중인 소켓이 변화가 있어야 반환을 한다. 그래서 변화가 없으면 select함수는 계속 블로킹을 하고 있을 것이다. 이러한 상황을 위해 timeout을 설정하는 것이다. timeout을 설정할 때 필요한 구조체가 이미 존재한다.
typedef struct timeval {
long tv_sec;
long tv_usec;
} TIMEVAL, *PTIMEVAL, *LPTIMEVAL;
각각 초, 밀리초를 넣어주면 된다.
Select 함수 호출
select 함수 구성
#include<winsock2.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout);
- nfds:리눅스 함수와 인터페이스를 맞추기 위한 인자
- readfds: 입력 관찰 set
- writefds: 출력 관찰 set
- exceptfds: 예외 관찰 set
- timeout: timeout
-> 성공 시 0 이상, 실패 시 -1 반환
timeout이 없이 계속 기다리고 싶다면?? -> nullptr를 넣어주면 된다!
Select 호출 이후 결과 확인
그럼 어떤 식으로 Select는 결과가 나올까?
Select 함수를 호출하게 되면, 3개의 set에 변화가 발생한(현재 입출력 함수를 실행할 수 있는) 소켓만 남게 된다.
그 후 이 소켓을 이용해 입/출력을 진행하면 된다.
단점
앞서 말한 것 처럼 select 함수를 실행하면 입출력 함수를 실행 할 수 있는 소켓만 남기 때문에 또 다시 fd_set을 비우고, 등록하고 하는 작업을 반복해야한다....
또한 소켓이 fd_set에 존재하는지 알기 위해 fd_set 전체를 for문으로 돌며, FD_ISSET 작업을 해줘야한다..!
마무리
내가 공부하는 게임 서버는 통상적으로 iocp 입출력 모델로 제작된다. 하지만 이번에 알아본 함수는 가장 기본이 되는 select 모델에 사용되는 select 함수다.
iocp만 배우면 안될까..? 라고 생각이 들 수 있지만, 클라이언트에 네트워크를 연동하게 된다면, 클라이언트는 자기 자신만 신경 쓰면 되기 때문에, iocp모델까지 가지 않아도 select모델만으로도 충분하다!
그러니 iocp 모델 또한 중요하지만, 기본이 되는 select모델도 알아두면 좋을 것 같다.
참고
'TCP-IP 소켓 프로그래밍' 카테고리의 다른 글
스레드의 동기화를 이해해보자 (1) | 2023.09.11 |
---|---|
스레드와 프로세스의 차이를 이해해보자 (5) | 2023.09.11 |
Nagle 알고리즘을 이해해보자 (0) | 2023.09.04 |
주소할당 에러(Binding Error)를 이해해보자 (1) | 2023.09.04 |
TCP 소켓의 우아한 연결종료(Half-close)를 이해해보자 (1) | 2023.08.31 |