본문 바로가기
Develop/Network

[윤성우의 열혈 TCP/IP 소켓 프로그래밍] Chapter21 - 내용 확인 문제 풀이

by Tarra 2023. 7. 2.

 

 

 

 

 [윤성우의 열혈 TCP / IP 소켓 프로그래밍] 책을 기반으로 개인적으로  문제 풀이 및 개념을 정리한 내용입니다.

모든 소스 코드와 강의, 확인 문제의 정확한 답안은 (23년 7월 1일부터 전면 무료화 예정)

http://www.orentec.co.kr/

 

====== 오렌지 미디어 ======

 

www.orentec.co.kr

에서 확인할 수 있습니다.

 

 


 

01. 동기 입출력과 비동기 입출력이 무엇인지, send & recv 함수를 기준으로 설명해보자. 그리고 동기 입출력의 단점은 무엇이고 이것이 비동기 입출력을 통해서 어떻게 해결이 되는지도 함께 설명하자.

동기 입출력(Synchronous IO)은 호출된 함수가 입출력 작업이 완료될 때까지 대기하는 방식이다.

예를 들어, send 함수는 데이터를 보내고 난 후에 데이터가 완전히 전송될 때까지 대기하고, recv 함수는 데이터를 받을 때까지 대기한다.

이러한 동기 입출력 방식은 호출한 함수가 입출력 작업을 처리하는 동안 다른 작업을 수행하지 못하고 대기해야 한다는 특징을 가지고 있다.

 

반면에 비동기 입출력(Asynchronous IO)은 입출력 작업을 호출한 후에도 호출한 함수가 바로 반환되어 다른 작업을 수행할 수 있다.

입출력 작업의 완료는 이벤트 또는 콜백 함수를 통해 알려지며, 알림을 받은 후에 데이터를 확인하거나 추가 작업을 수행할 수 있다.

비동기 입출력 방식은 호출한 함수가 입출력 작업을 대기하지 않고도 다른 작업을 수행할 수 있기 때문에 효율적인 자원 활용과 더 높은 처리량을 가질 수 있다.

 

동기 입출력의 단점은 입출력 작업이 완료될 때까지 대기해야 한다는 점이다.

이는 호출한 함수가 다른 작업을 수행하지 못하고 블로킹되어 프로그램의 응답성과 처리량을 저하시킬 수 있다.

특히, 입출력 작업의 시간이 오래 걸리는 경우에는 전체 프로그램의 성능에 영향을 미칠 수 있다.

 

비동기 입출력은 이러한 단점을 해결하기 위해 사용된다.

비동기 입출력에서는 호출한 함수가 입출력 작업을 대기하지 않고 다른 작업을 수행할 수 있으므로, 

입출력 작업이 오래 걸려도 다른 작업을 동시에 처리할 수 있다.

이는 프로그램의 응답성을 향상시키고, 여러 입출력 작업을 동시에 처리할 수 있는 병렬성을 제공한다.

 

요약하면, 동기 입출력은 호출한 함수가 입출력 작업의 완료를 기다리는 반면에 비동기 입출력은 호출한 함수가 입출력 작업의 완료를 기다리지 않고 다른 작업을 수행할 수 있다.

 

더보기

모범 답안

동기 입출력이란 데이터의 송수신이 완료되는 시점이 호출된 함수가 반환을 하는 시점과 일치하는 입출력 방식을 말한다.

즉, send 함수가 반환을 하는 시점이 데이터의 전송이 완료되는 시점이고, 

recv 함수가 반환을 하는 시점이 데이터의 수신이 완료되는 시점이다.

그러나 비동기 입출력은 데이터의 송수신이 완료되는 시점과 상관없이 호출된 함수가 반환되는 입출력 방식이다.

동기 입출력의 단점은 입출력이 완료될 때까지 블로킹 상태에 놓인다는 점이다.

이 시간에는 사실 CPU의 연산이 거의 수반되지 않음에도 불구하고 블로킹 상태에 놓여서 다른 작업을 진행할 수 없게 된다.

이런 측면에서 볼 때 비동기 입출력은 CPU를 보다 효율적으로 사용하는 입출력 방식이라 할 수 있다.

 

 

02. 모든 경우에 있어서 비동기 입출력이 최선의 선택이 될 수는 없다. 그렇다면 비동기 입출력의 단점은 무엇인가? 그리고 어떠한 경우에 동기 입출력이 좋은 선택이 될 수 있겠는가? 이에 대한 답을 내리기 위해서 비동기 입출력 관련 소스코드를 참고하기 바라며, 쓰레드와 관련해서도 여러분의 의견을 제시하기 바란다.

비동기 입출력의 단점은 다음과 같다.

1. 복잡성

비동기 입출력은 동기 입출력에 비해 구현이 더 복잡하다.

이벤트 루프나 콜백 함수 등 추가적인 코드 작성과 관리가 필요하다.

이로 인해 코드의 가독성과 유지보수성이 떨어 질 수 있다.

 

2. 오버헤드

비동기 입출력은 추가적인 이벤트 핸들링이 필요하므로 오버헤드가 발생할 수 있다.

이벤트의 생성, 처리, 관리 등의 작업에 따른 성능저하가 발생할 수 있다.

 

3. 복잡한 오류처리

비동기 입출력은 입출력 작업이 완료되었을 때, 알림을 받아 처리해야 한다.

이는 오류 처리가 복잡해질 수 있으며, 알림을 정확하게 처리하지 않으면 리소스 누수 또는 오작동의 원인이 될 수 있다.

 

동기 입출력이 좋은 선택이 될 수 있는 경우는 다음과 같다.

1. 간편한 구현과 이해

동기 입출력은 호출한 함수가 입출력 작업의 완료를 기다리는 방식이기 때문에 구현과 이해가 비교적 간단하다.

복잡한 비동기 입출력보다 단순하고 직관적인 코드를 작성할 수 있다.

 

2. 단일 작업 흐름

동기 입출력은 호출한 함수가 입출력 작업의 완료를 기다리기 때문에 작업이 완료될 때까지 다른 작업을 수행하지 않는다.

이는 작업의 순서를 보장하고, 데이터의 일관성을 유지할 수 있는 장점을 가진다.

 

3. 동기화와 관련된 이슈

동기 입출력은 입출력 작업의 완료를 기다리는 동안 다른 스레드가 접근하지 못하도록 동기화가 자연스럽게 이루어진다.

따라서 여러 스레드가 동시에 접근할 수 있는 데이터에 대해서는 동기 입출력이 더 적합한 선택이 될 수 있다.

 

쓰레드와 관련하여, 동기 입출력은 단일 스레드에서 입출력 작업을 처리하는 경우에 효과적이다.

단일 스레드에서는 동기 입출력을 사용하여 작업의 순서와 데이터의 일관성을 보장할 수 있다.

하지만 멀티스레드 환경에서 동기 입출력을 사용하는 경우, 다른 스레드들이 입출력 작업의 완료를 기다려야 하므로 전체적인 성능이 저하될 수 있다.

이 경우에는 비동기 입출력이 더 적합한 선택이 될 수 있다.

따라서 멀티스레드 환경에서는 동기 입출력과 비동기 입출력은 상황에 맞게 선택하는 것이 중요하다.

 

더보기

모범 답안

비동기 입출력의 장점이자 단점은 입출력의 완료를 이후에 확인해야 한다는 것이다.

이는 서버의 서비스 형태가 매우 간단하고, 응답에 필요한 데이터의 크기가 작은 경우에는 불편하게 느껴질 수 있다.

특히 클라이언트 하나당 쓰레드를 하나씩 생성하는 서버 모델에서는 굳이 비동기로 입출력을 진행할 필요가 없다.

 

 

03. select 방식과 관련된 다음 설명이 맞으면 O, 틀리면 X를 표시해보자.

- select 방식은 호출된 함수의 반환을 통해서 IO 관련 이벤트의 발생을 알리니, Notification IO 모델이라 할 수 있다. (O)

- select 방식은 IO 관련 이벤트의 발생시점과 호출된 함수의 반환시점이 일치하기 때문에 비동기 모델이 아니다. (O)

- WSAEventSelect 함수는 select 방식의 비동기 모델이라 할 수 있다. IO 관련 이벤트의 발생을 비동기의 형태로 알리기 때문이다. (O)

 

 

04. select 함수를 이용하는 방식과 WSAEventSelect 함수를 이용하는 방식의 차이점을 소스코드의 관점에서 설명해보자.

'select' 함수와 'WSAEventSelect' 함수는 모두 네트워크 프로그래밍에서 비동기 입출력은 구현하는 데 사용되는 함수이다.

하지만 'select' 함수는 POSIX 표준에 따라 리눅스와 유닉스 기반 시스템에서 사용되는 반면, 'WSAEventSelect' 함수는 윈도우 운영체제에서 사용되는 함수이다.

 

1. select 함수

- select 함수는 여러 개의 소켓을 한 번에 관찰하면서 해당 소켓들의 상태 변화를 비동기적으로 감지하는데 사용된다.

- 파일 디스크립터 집합을 매개변수로 받아서, 해당 집합에 대해 읽기, 쓰기, 예외 상태등의 변화를 체크할 수 있다.

- 단일 스레드에서 여러 소켓을 모니터링하므로 멀티스레드 환경에서는 비효율적이다.

- 파일 디스크립터 집합을 직접 수정해야 하므로 매번 새로운 집합을 만들어야 한다.

 

2. WSAEventSelect 함수

- WSAEventSelect 함수는 윈도우 소켓 프로그래밍에서 비동기 입출력을 구현하는데 사용된다.

- 소켓에 이벤트 객체를 연결하여 해당 소켓의 상태 변화를 비동기적으로 감지한다.

- 윈도우의 이벤트 객체를 사용하므로 WSAEventSelect 함수는 리눅스와 유닉스 기반 시스템에서는 사용할 수 없다.

- WSAEventSelect 함수는 WSAWaitForMultipleEvents 함수와 함께 사용되어 여러 소켓의 상태 변화를 비동기적으로 처리할 수 있다.

- 각 소켓에 대한 이벤트 객체를 만들어야 하므로 리소스 사용면에서 약간의 오버헤드가 있을 수 있다.

 

더보기

모범 답안

select 함수를 이용할 경우 관찰의 대상이 되는 핸들의 정보를 select 함수호출 시마다 매번 전달해야 한다.

반면에, WSAEventSelect 함수를 이용할 경우에는 관찰대상의 정보를 운영체제게 기록해 두기 때문에 매번 전달할 필요가 없다.

그리고 select 함수를 이용할 경우, 이벤트가 발생할 때까지 블로킹 상태에 있어야 하지만, 

WSAEventSelect 함수를 이용할 경우에는 이벤트가 발생할 때까지 블로킹 상태에 있을 필요가 없다.

일단 호출한 WSAEventSelect 함수를 빠져 나와서 이후에 별도의 과정을 거쳐서 이벤트의 발생유무를 확인하면 된다.

 

 

05. Chapter 17에서 소개한 epoll은 엣지 트리거 모드와 레벨 트리거 모드로 동작한다. 그렇다면 이 중에서 비동기 입출력이 잘 어울리는 모드는 무엇인가? 그리고 그 이유는 무엇인가? 이와 관련해서 포괄적인 답을 해보자. 

epoll은 엣지 트리거 모드와 레벨 트리거 모드로 동작할 수 있지만, 비동기 입출력에서는 엣지 트리거 모드가 더 잘 어울린다.

엣지 트리거 모드는 데이터의 변화가 발생한 순간에만 이벤트를 발생시키기 때문에 비동기 입출력과의 조합으로 효과적인 처리가 가능하다.

 

비동기 입출력은 데이터의 변화가 발생할 때까지 블로킹되지 않고 다른 작업을 수행하는 방식이므로,

레벨 트리거 모드에서는 epoll_wait 함수가 호출될 때마다 입출력 가능한 모든 파일 디스크립터를 반환하여 처리해야 한다.

이는 시스템 자원을 비효율적으로 사용하게 되며, 많은 파일 디스크립터를 처리할 경우네는 성능 저하가 발생할 수 있다.

 

반면, 엣지 트리거 모드에서는 데이터의 변화가 발생한 순간에만 이벤트가 발생하므로,

epoll_wait 함수가 호출되어도 실제로 변화가 발생한 파일 디스크립터만 반환된다.

이는 입출력 가능한 파일 디스크립터의 수가 많을 때에도 불필요한 시스템 호출을 최소화하여 성능을 향상시킬 수 있다.

 

따라서 비동기 입출력과 함께 사용될 때는 epoll의 엣지 트리거 모드가 더 적합하다.

 

더보기

모범 답안

비동기 입출력이 잘 어울리는 모드는 엣지 트리거 모드이다. 

엣지 트리거 모드는 입력버퍼에 데이터가 남아있다고 해서 이벤트를 등록하지는 않는다.

즉, 엣지 트리거 모드에서는 비동기로 입출력이 진행중인 상황에 대해서는 이벤트를 등록하지 않기 때문에,

새로 등록되는 이벤트에 대해서만 신경을 쓰면 된다.

그러나 레벨 트리거 모드에서는 입력버퍼에 데이터가 남아있는 상황에서도 이를 이벤트로 등록한다.

따라서 레벨 트리거 보드에서 비동기로 입출력을 진행할 경우, 새로 등록된 입출력과 처리중인 입출력의 구분이 불가능하기 때문에 

코드의 구현에 큰 어려움을 겪게 된다.

 

 

06. 리눅스의 epoll 역시 비동기 입출력 모델이라 할 수 있다. 그렇다면 이를 비동기 입출력 모델이라 할 수 있는 이유에 대해서 설명해보자.

1. 이벤트 기반 

epoll은 이벤트 기반으로 동작한다.

이벤트 기반 모델은 데이터의 도착이나 변화와 같은 이벤트가 발생할 때만 작업을 처리하고, 이외의 시간에는 블로킹되지 않고 다른 작업을 수행할 수 있다.

따라서 비동기 입출력과 잘 어울리며, 입출력 작업이 발생할 때만 이벤트가 발생하여 처리할 수 있다.

 

2. 다중 입출력 처리

epoll은 다중 파일 디스크립터를 관리하고 모니터링 할 수 있다.

여러 개의 파일 디스크립터에 대한 입출력 이벤트를 모니터링하여 효율적으로 처리할 수 있다.

이는 비동기 입출력 작업이 동시에 발생하는 상황에서 유용하며, 입출력 이벤트가 발생한 파일 디스크립터만 처리함으로써 성능을 개선할 수 있다.

 

3. 비동기적인 동작

epoll을 사용하면 입출력 작업을 논블로킹으로 처리할 수 있다.

이는 입출력 작업이 완료되지 않은 상태에서도 다른 작업을 처리할 수 있음을 의미한다.

따라서 입출력 작업이 끝나기를 기다리지 않고, 다른 작업을 수행할 수 있어 전체적인 프로그램의 성능과 응답성을 향상시킬 수 있다.

 

4. 효율적인 이벤트 관리

epoll은 내부적으로 효율적인 이벤트 관리를 위해 커널의 기능을 사용한다.

이를 통해 대규모 파일 디스크립터를 효율적으로 관리하고 이벤트를 처리할 수 있다.

이는 많은 입출력 작업이 동시에 발생하는 상황에서도 높은 성능을 유지할 수 있게 해준다.

 

더보기

모범 답안

epoll 방식도 이벤트의 관찰 대상을 등록하는 과정과 이벤트의 발생을 확인하는 과정이 별도의 함수로 구분되어 있다.

따라서 이벤트가 발생한 이후에 원하는 시점에서 이벤트의 발생 유무를 확인할 수 있다.

그러므로 epoll 역시 비동기 입출력 모델이라 할 수 있다.

 

 

07. WSAWaitForMultipleEvents 함수가 관찰할 수 있는 최대 핸들의 수는 어떻게 확인이 가능한가? 이의 확인을 위한 코드를 작성해서, 이 값을 실제로 확인해보자.

 

WSA_MAXIMUM_WAIT_EVENTS의 값을 확인하면 된다.

 

 

08. 비동기 Notification IO 모델에서 Event 오브젝트가 manual-reset 모드여야 하는 이유를 설명해보자.

1. 다중 스레드 환경에서의 안정성

비동기 Notification IO 모델에서는 여러 개의 스레드가 동시에 작업을 수행할 수 있다.

이때 Event 오브젝트가 manual-reset 모드일 경우, 여러 스레드가 동시에 해당 Event 오브젝트의 상태를 확인하고 신호를 처리할 수 있다.

이는 다중 스레드 환경에서 안정성을 보장하고, 잘못된 신호 처리나 경쟁 상태 등을 방지하는데 도움이 된다.

 

2. 신호의 지속성 유지

manual-reset 모드에서 Event 오브젝트는 신호가 설정된 상태로 유지된다.

따라서 한 번 설정된 신호는 스레드가 신호를 처리하더라도 자동으로 초기화되지 않는다.

이는 신호가 지속되어야 하는 상황에서 유용하며, 다수의 스레드가 동시에 해당 신호를 처리해야 하는 경우에도 신호를 유지할 수 있다.

 

3. 신호 소실 방지

manual-reset 모드에서는 신호가 설정된 Event 오브젝트를 기다리는 스레드가 없어도 신호가 유지된다.

이는 신호를 놓치거나 소실하는 상황을 방지할 수 있다.

예를 들어, 스레드가 Event 신호를 기다리고 있는 도중에 다른 이벤트가 발생하여 스레드가 차단되지 않는 경우에도 신호를 유지할 수 있다.

 

4. 동기화 제어

manual-reset 모드에서 Event 오브젝트는 여러 스레드 간의 동기화에 사용될 수 있다.

스레드는 신호의 상태를 확인하고, 필요에 따라 대기하거나 작업을 수행할 수 있따.

manual-reset 모드는 스레드 간의 상호작용을 제어하고 동기화를 가능하게 해준다.

 

더보기

모범 답안

이벤트의 발생유무를 확인하기 위해서 1차로 WSAWaitForMultipleEvents 함수가 호출되는데, 

이 함수의 호출 이후에 실제 이벤트의 발생대상을 찾기 위해서 2차로 WSAWaitForMultipleEvents 함수를 호출해야 한다.

따라서 manual-reset 모드가 아니라면, 자동으로 non-signaled 상태로 변경되기 때문에 2차로 WSAWaitForMultipleEvents 함수를 호출할 수 없게 된다.

 

 

09. 이번 Chapter에서 설명한 비동기 Notification IO 모델을 바탕으로 채팅 서버를 구현해보자. 이 채팅 서버는 Chapter 20에서 소개한 채팅 클라이언트인 예제 chat_clnt_win.c와 함께 동작이 가능해야 한다.

 

(생략)

 

 

 


출처 : [윤성우의 열혈 TCP / IP 소켓 프로그래밍] / 윤성우 저 / 오렌지 미디어

https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com