본문 바로가기

프로그래밍/Etc

[Etc] Blocking, non-Blocking and Asyschronous mode

윈속의 동작모드

▶ BSD 소켓과 마찬가지로 윈속이 제공하는 소켓도 다음과 같은 세 가지 동작모드 (operating mode)를 가지고 있다.

Blocking 모드
Non-blocking 모드
Asynchronous(비동기) 모드
(1) Blocking 모드

▶ socket() 시스템 콜을 호출하여 하나의 소켓을 만들면 이것은 디폴트로 blocking 모드로 동작하는 소켓이 된다.

▶ 이러한 blocking 모드의 소켓을 대상으로 accept(), close- socket(), connect(), recv(), recvfrom(), send(), sendto()와 같은 함수를 호출하면 함수가 원하는 동작을 완료할 때까지 함수를 호출한 프로세스가 blocking될 수 있다.

▶ 즉, blocking 모드의 소켓에서는 응용 프로그램에서 위와같은 함수를 호출하였을 때 그 동작이 완료되어 함수가 리턴되어야 다음 작업을 할 수 있게 된다.

▶ 한편 멀티태스킹이 지원되는 UNIX 컴퓨터에서는 block- ing 모드의 소켓을 사용하여 어떤 응용 프로그램이 블록되어도 컴퓨터 전체 동작에는 큰 문제가 되지 않는다.

▶ 왜냐하면 멀티태스킹 운영체제에서는 각각의 프로세스들이 독립적으로 수행되므로 한 프로세스가 블록되어 있어도 다른 프로세스들은 계속 수행될 수 있기 때문이다.

▶ 그러나 윈도우3.1과 같은 단일 태스킹 운영체제에서는 프로그램이 한 곳에 블록되어 있으면 PC 전체가 블록될 수 있다.

▶ 또한 blocking 모드의 소켓을 사용하면 하나의 프로그램에서 여러 개의 소켓을 동시에 개설하여 각각의 입출력을 처리하는 형태의 응용 프로그램을 작성하기가 어렵다.

▶ 따라서 윈속 프로그래밍에서는 이를 해결하기 위하여 소켓을 non-blocking 모드 또는 비동기 모드로 변경하여 사용하는 것이 필요하다.

(2) Non-blocking 모드

▶ Non-blocking 모드 소켓이란 accept(), closesocket(), connect(), recv(), recvfrom(), send(), sendto()와 같은 함수가 호출되었을 때 함수의 원하는 동작이 완료되는 것과 무관하게 일단 함수가 즉시 리턴되는 소켓을 말한다.

▶ 소켓이 처음 만들어지면 디폴트로 blocking 모드가 되는데 프로그래머는 필요에 따라 blocking 모드의 소켓을 non-blocking 모드로 바꿀 수 있다.

▶ Non-blocking 모드의 소켓을 사용하는 이유는 응용 프로그램이 이곳에서 멈추어 있지(block) 않게 하기 위해서이다.

▶ Non-blcoking 모드의 소켓에서 함수 호출이 즉시 리턴되었을 때 그 결과는 다음과 같이 두 가지로 종류로 나눌 수 있다.

1) 성공적인 리턴: 함수의 동작이 즉시 성공적으로 수행되었음.

2) 에러 리턴: 함수 수행중 에러가 발생했거나 함수가 블록되었음.

▶ 즉, non-blocking 모드 소켓에서 즉시 리턴된 함수 호출 결과는 성공적인 경우도 있고 실패한 경우도 있을 수 있다.

▶ 에러 리턴인 경우 에러코드가 WSAEWOULDBLOCK이면, 이것의 의미는 함수의 동작이 잘못되었다는 것이 아니라 '이 함수가 동작 완료될 때까지 기다린다면 block될 수 있다'는 것을 의미한다.

▶ 이와같이 에러코드가 WSAEWOULDBLOCK인 경우 그 원인은 다음의 두 가지 중 하나가 된다.

1) Winsock.dll이 함수가 원하는 동작을 시작했으나 아직 종료되지 않았음.

2) 함수의 동작이 시작되지 못했으며 다시 재시도를 필요로 함.

▶ 위의 첫번째 경우는 응용 프로그램이 함수의 동작 완료 시점을 알아서 그 결과를 처리하여야 하며 두번째 경우는 응용 프로그램이 이 함수가 성공적으로 시작될 때까지 함수를 계속 반복하여 호출해야 한다.

▶ 어떤 경우이든 non-blocking 모드 소켓의 처리는 다소 복잡하며 따라서 다음에 설명할 비동기 모드를 사용하는 것이 편리하다.

(3) Asynchronous(비동기) 모드

▶ 비동기 모드에서도 non-blocking 모드에서처럼 소켓 관련 함수의 호출이 바로 리턴된다.

▶ 그러나 비동기 모드에서는 non-blocking 모드와 달리, 함수의 동작이 완료되는 시점, 또는 함수의 실행이 시작되지 못한 경우 다음에 다시 재시도하여야 하는 시점을 시스템(Winsock.dll)이 메시지 처리 방식으로 나중에 응용 프로그램에게 알려준다.

▶ 즉, 비동기 모드의 소켓에서 소켓관련 함수의 실행결과의 에러코드가 WSAEWOULDBLOCK일 때의 의미는 다음과 같다.

1) 함수의 동작이 완료되면 그 때 Winsock.dll이 메시지를 통하여 동작의 완료를 알려주거나,

2) 함수의 동작이 시작하지 못했으며, 함수를 다시 호출해야 할 시점을 나중에 비동기적으로 알려주겠음.

▶ 앞에 언급한 바와 같이 UNIX와 같은 운영체제에서는 함수가 블록되는 것이 문제가 되지 않으므로 반드시 비동기 모드의 소켓을 사용할 필요는 없다.

▶ 그러나 윈속에서는 비동기 모드로 소켓을 사용하는 것이 편리하다.

(4) Blocking 함수

▶ 한편 blocking 모드의 소켓이 아니더라도 (즉, non- blocking 또는 비동기 모드의 소켓에서도) 어떤 함수들은 함수 자체의 특성상 블록될 수 있는 함수가 있다.

▶ 이러한 함수들은 네트웍 시스템(즉, TCP/IP)이 어떤 정보를 얻어내야만 그 결과를 리턴할 수 있으며 그 정보를 얻는데 다소 시간이 필요하기 때문이다.

▶예를들어 호스트의 도메인 네임을 입력하고 이 호스트의 IP 주소 등의 정보를 얻어내는 함수 gethostbyname()이 처리되기 위하여는, 네트웍 시스템이 DNS 서버에게 필요한 정보를 문의하고 그 결과가 도착할 때까지 기다려야만 한다.

▶ 이러한 함수들을 'blocking 함수'라고 부르며 표 5-1에 대표적인 blocking 함수들을 정리하였다.

함 수
기 능

select() 소켓의 상태 변화(읽기, 쓰기, 오류 발생)를 알려줌
gethostbyaddr() 호스트 주소로부터 호스트 정보를 얻음
gethostbyname() 호스트 이름으로부터 호스트 정보를 얻음
getprotobyname() 프로토콜 이름으로부터 프로토콜 번호를 얻음
getprotobynumber() 프로토콜 번호로부터 프로토콜 이름을 얻음
getservbyname() 서비스 이름으로부터 서비스 정보를 얻음
getservbyport() 포트번호로부터 서비스 정보를 얻음

표 5-1 대표적인 blocking 함수

▶ 표 5-1에 소개한 blocking 함수들은 소켓의 동작 모드에 관계없이 항상 블록될 수 있는 함수이다

▶ 이러한 함수를 사용할 때 프로그램이 블록되는 문제를 해결하기 위하여, 윈속에서는 이들 blocking 함수와 같은 기능을 수행하면서 실제로는 비동기 모드로 동작하는 즉, 함수 실행결과를 비동기적으로 알려주는 비동기 함수들을 제공하고 있다.

▶ 이들을 표 5-2에 정리하였으며 자세한 내용은 5.2.2절에서 설명하겠다.

비동기 함수
기 능

WSAAsyncSelect() 소켓의 I/O 상태 변화 즉, 연결요청, 데이터 수신, 송신 버퍼의 사용가능 등의 이벤트를 시스템이 메시지를 통하여 알려주도록 요청함
WSAAsyncGetHostByAddr() 호스트 주소로부터 호스트 정보를 얻음
WSAAsyncGetHostByName() 호스트 이름으로부터 호스트 정보를 얻음
WSAAsyncGetProtoByName() 프로토콜 이름으로부터 프로토콜 번호를 얻음
WSAAsyncGetProtoByNumber() 프로토콜 번호로부터 프로토콜 이름을 얻음
WSAAsyncGetServByName() 서비스 이름으로부터 서비스 정보를 얻음
WSAAsyncGetServByPort() 포트번호로부터 서비스 정보를 얻음

표 5-2 Blocking 함수(표 5-1)의 기능을 수행하는 윈속의 비동기 함수

소켓의 동작모드

▶ 소켓의 동작모드에는 blocking, non-blocking, 비동기(asynchronous) 모드

 세 가지가 있다.

blocking 모드

     소켓을 처음 생성하면 디폴트로 blocking 모드가 되는데, 이 소켓에 대

    해 어떤 시스템 콜을 호출하였을 때 네트워크 시스템(즉, TCP/IP)이 동작

    을 완료할 때까지 그 시스템 콜에서 프로세스가 멈추어 있게 된다.

      block 될 수 있는 소켓 시스템 콜은 listen(), connect(), accept(),

    recv(), send(), read(), write(), recvfrom(), sendto(), close() 등이다.

      일 대 일 통신을 하거나 프로그램이 한가지 작업만 하면 되는 경우는 blocking 모드로 프로그램을 작성할 수 있다.

Non-blocking 모드

      소켓 관련 시스템 콜에 대하여 네트워크 시스템이 즉시 처리할 수 없

    는 경우라도 시스템 콜이 바로 리턴되어 응용 프로그램이 block되지 않게

    하는 소켓 모드

      통신 상대가 여럿이거나 여러 가지 작업을 병행하려면 non-blocking

    또는 비동기 모드를 사용하여야 한다.

      non-blocking 모드를 사용하는 경우에는 일반적으로 어떤 시스템 콜

    이 성공적으로 실행될 때까지 계속 루프를 돌면서 확인하는 방법(폴링)을

    사용한다.

      유닉스에서는 fcntl() 시스템 콜을 사용하여 소켓을 non-blocking 모드

    로 바꿀 수 있다.

비동기 모드

      소켓에서 어떤 I/O 변화가 발생하면 (데이터의 도착 등) 그 사실을 응

    용 프로그램이 알 수 있도록 하여  그 때 원하는 동작을 할 수 있게 하는

    모드

      전화에서 상대방과 통화할 수 없을 때 전화를 걸어 달라고 부탁하고

    끊는 것과 유사하다.

      소켓을 비동기 모드로 바꾸는 방법에는, select() 함수를 이용하는 방

    법, 그리고 fcntl()를 사용하여 소켓을 signal-driven I/O 모드로 바꾸는 방

    법이 있다.

      select()를 이용하는 방법은 I/O 변화가 발생할 수 있는 소켓 전체를

    대상으로 select()를 호출해 두면  그 중 임의의 소켓에서 I/O 변화가 발생

    되었을 때 select()문이 리턴되고 이 때 원하는 작업을 하는  방법이다.

      signal-driven I/O 방법은 특정 소켓에서 I/O 변화가 발생하였을 때 그

    소켓이 SIGIO 시그널을  발생시키도록 하고 응용 프로그램에서는 이 시그

    널을 받으면 필요한 작업을 하도록 하는 방법이다.

     

    Synchronous vs Asynchronous

    The send, receive, and reply operations may be synchronous or asynchronous. A synchronous operation blocks a process till the operation completes. An asynchronous operation is non-blocking and only initiates the operation. The caller could discover completion by polling, by software interrupt, or by waiting explicitly for completion later. (Does it make sense to have an RPC send not block?) An asynchronous operation needs to return a call/transaction id if the application needs to be later notified about the operation. At notification time, this id would be placed in some global location or passed as an argument.

    The notion of synchronous operations requires an understanding of what it means for an operation to complete. In the case of remote assignment, both the send and receive complete when the message has been delivered to the receiver. In the case of remote procedure call, the send, receive, and reply complete when the result has been delivered to the sender, assuming there is a return value. Otherwise, the send and receive complete when the procedure finishes execution. During the time the procedure is executing, the sender and receiver are in a rendezvous, as mentioned before.

    Note that synchronous/asynchronous implies blocking/not blocking but not vice versa, that is, not every blocking operation is synchronous and not every non blocking operation is asynchronous. For instance, a send that blocks till the receiver machine has received the message is blocking but not synchronous since the receiver process may not have received it. Similarly, we will see later a Xinu receive that is non-blocking but is not asynchronous. These definitions of synchronous/asynchronous operations are similar but not identical to the ones given in your text books, which tend to equate synchronous with blocking.

    Asynchronous message passing allows more parallelism.

    it can do some computation while the message is in transit. In a synchronous system, such parallelism can be achieved by forking a separate process for each concurrent send, but this approach incurs the cost of extra process management. This cost is typically bearable with lwps but not hwps.

    Asynchronous message passing introduces several problems. What happens if the message cannot be delivered? The process never waits for delivery of the message, and thus never hears about the error. Software interrupts could be used to report such errors. Another problem related to asynchronous communication is to do with buffering. If messages sent asynchronously are buffered in a space managed by the OS, then a process may fill this space by flooding the system with a large number of messages.

 네트워크 소켓 프로그래밍 관련 자료