c++ socket programming 을 하던 중 select api 가 어떻게 동작하는지 알지 못해서 코드를 읽는 도중에 흐름이 끊겼다.
알아보고 지나가자. 또한 inet_ntop api 에 대해서도 간략하게 알아보자.
select api 를 설명하기 전에 멀티플렉싱 서버에 대해 설명해야한다.
멀티플렉싱 서버란 하나의 프로세스로 여러 클라이어트에 서비스를 하는 서버이다.
멀티플렉싱 서버에서는 하나의 프로세스가 서버 소켓 + 여러 클라이언트 소켓을 관리한다.
관리할때 fd_set 이라는 구조체를 사용한다고 보면 된다.
이 fd_set 은 배열 형태인데 인텍스로 매핑하기 위해 쓴다고 보면 된다. 그냥 bit array 에 특정 index 에 체크해준다고 생각하면 된다.
아래와 같은 함수가 있다.
FD_ZERO -> 초기화할때 쓰인다. 전부 0으로 세팅한다고 보면 된다.
FD_SET -> 세팅할때 쓰인다.
FD_CLR -> 세팅한 내용을 지울때 쓰인다.
FD_ISSET -> 세팅되었는지 체크할때 쓰인다.
그리고 이제 select api를 통해 어느 소켓의 fd에 read, write, exception이 발생했는지 확인할 수 있다.
select api를 소개하자면 이 api는 일단 입출력 다중화를 위해 쓰인다.
입출력 다중화는 여러 개의 파일을 다루기 위해서 파일 기술자 즉 FD를 배열 즉 그룹으로써 관리한다.
데이터 변경을 감시할 파일 기술자인 File Descriptor 를 배열에 포함시키고 배열에 포함된 파일 기술자에
읽기 혹은 쓰기, 에러와 같은 데이터 변경이 발생하면 파일 기술자에 대응되는 배열에 표시하는 방식이다.
표시를 했으니 나중에 개발자가 이 파일 디스크립터의 배열의 값을 검사하는 것으로 여러 개의 파일을
처리할 수 있는 것이다.
물론 이런 방식에서 단점이 있는데 파일 디스크립터를 표시하는 배열인 FD 테이블의 크기 제한이 있다는 것이다.
또한 배열 자체의 성능 문제도 있다고 한다. 배열의 모든 값을 검사해야하기 때문이다.
그리고 병렬 처리가 아니라는 단점도 있다고 한다. 데이터를 읽고 처리하고 응답하는 시간 동안 다른 파일이 대기해야하기 때문에 데이터 처리 과정이 긴 서비스에 적합한 모델이 아니라고 한다. 그러니 메시지 전송과 같은 서비스에 적합할 것 같다.
개념 자체가 꽤나 간단해서 많이 쓰인다고 한다.
이제 select 함수의 형태를 살펴보자.
int select(int nfds, fd_set *read_fds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
매개변수를 살펴보자면 아래와 같다.
1. nfds: 총 관리 파일의 개수이다. 파일의 개수를 최대 파일 지정 번호 + 1 로 지정하면 된다고 한다.
2. readfds: 읽을 데이터가 있는지 검사하기 위한 파일 목록이다.
3. writefds: 쓰여진 데이터가 있는지 검사하기 위한 파일 목록이다.
4. exceptfds: 파일에 예외 사항들이 있는지 검사하기 위한 파일 목록이다.
5. timeout: select ㅎ마수가 fd_set에 등록된 파일들에 데이터 변경이 있는지를 timeout 동안 기다린다고 한다.
만약 timeout 시간 동안 변경이 없으면 0을 반환한다고 한다. timeout 을 NULL로 지정하면 데이터가 있을 때까지
무한정 기다리고 멤버 값이 모두 0이면 즉시 반환한다고 한다.
변경된 데이터가 있으면 해당 비트값이 1로 설정된다. 그리고 비트 값을 검사하면서 어떤 파일 지정 번호에
데이터가 있는지 확인해서 읽기 혹은 쓰기를 하면 되는거다.
참고로 select 함수는 데이터가 변경된 파일의 목록을 리턴해주는게 아니라 데이터가 변경된 파일의 개수 즉 fd_set에서 비트값이 1인 필드의 객수를 반환한다.
단점이 하나 있는데 select 함수를 호출하기 이전에 fd_set의 값을 저장해야해서 매번 fd_set의 정보를 복사해야한다는 게 단점이라고 한다.
간략하게 요약하자면 readset이던, writeset이던 해당 비트 array에 실제로 1로 세팅을 해두고 FD_ISSET을 통해 지금 세팅된 곳이 있는지 체크하면서 원하는 로직을 진행하면 된다.
select 쪽이 이해가 가지 않으면 아래 유튜브 영상을 잠깐 보는 것도 도움이 된다.
https://www.youtube.com/watch?v=Y6pFtgRdUts
inet_ntop() 함수는 바이너리 형태의 IPv6 혹은 IPv4 주소 네트워크 정보(빅엔디안)를 문자열(리틀엔디언)으로 변환해주는 함수이다.
inet_pton() 함수는 문자열(리틀엔디언)을 바이너리 형태의 IPv6 또는 IPv4 주소 네트워크 정보(빅엔디언)으로 변환해주는 함수이다.
아래 세 곳의 블로그에서 많은 도움을 받았습니다.
감사합니다.
https://1d1cblog.tistory.com/356
https://www.joinc.co.kr/w/Site/system_programing/File/select
'C & C++ > C++' 카테고리의 다른 글
[C++] c++ 헷갈리는 개념 간단 정리(3) (0) | 2022.11.11 |
---|---|
[C++] C++ RapidJSON 라이브러리 사용법 (0) | 2022.11.10 |
[C++] C++ listen api 의 parameter 중 backlog. (0) | 2022.11.10 |
[C++] C++ 헷갈리는 개념 간단 정리 (2) (0) | 2022.11.09 |
[C++] Visual Studio 2022 에서 C++ rapidjson 사용하기 (0) | 2022.11.08 |