Java ServerSocket Blocking , Non-Blocking

Java 서버의 블록킹과 논블록킹에 대해 생각해보자.

일반 적인 설정의 톰캣과 같은 was는 다음과 같이 동작한다.

1.서버는 특정 포트를 대상으로 서버소켓을 연결하여 listening

2.클라이언트가 서버로 접속 요청

3.서버는 accept() 하여 소켓을 할당한다.

  • 여기 까지 생각했을때 서버는 accept 단계에서 블록킹되며.
    처리중 다른 클라이언트의 접근 요청을 받을 수 없다.

4.서버는 accept() 하여 할당한 소켓을 별도 스레드를 생성하여 처리한다.

5.클라이언트 요청에 대한 처리를 다른 스레드로 위임하였기 때문에 서버소켓은 또 다른 클라이언트의 요청을 받을수 있다.

  • 여기 까지가 일반적인 SeverSocket — Thread 방식의 처리이다.
  • 톰켓과 같은 WAS들은 nio 커넥터를 쓰지 않는다면 여기서 생성하는 Thread에 대한 Thread Pool을 추가적으로 적용?관리?하고 있다.
    (Thread가 무한히 늘어나면 시스템은 자원고갈..)

위에서 설명한 SeverSocket — Thread 방식의 문제점은
Thread를 사용함에 있다.
Thread를 사용하면서 많은 CPU 리소스를 사용하며,
많은 객체를 생성하고,
객체의 라이프사이클이 종료되고,
GC가 빈번히 일어나면서 full GC가 일어날때 스레드들은 멈춘다.
또한 리소스에 따라 한정적인 Thread를 사용할수 밖에 없다.
많은 수의 Connection 을 허용할순 있지만 전체적으로 느려지는 현상이 생김.

많은 트래픽에 대한 처리에는 다른 추가적인 방법이 필요.

그럼 이쯤에서 논블록킹에 대해 봐보자.

java에서는 java.nio.channels 패키지의 ServerSocketChannel등을 사용하고 있다.
Channel 이란 Stream과 같은 단방향성이 아니라 양방향성을 가지고 있다고 이해하면 되겠다.

네트워크 소녀 네티라는 책의 처음 부분에 나오는 논블록킹 서버 로직을 참고하면 간단하게 아래와 같이 정리 할수 있겠다.

서버는 싱글 스레드로 하나의 for loop 를 무한히 돌아간다.
이 loop안에서는 하나의 셀렉터를 사용하며.
사전에 서버소켓채널은 OP_ACCEPT 키로 셀렉터에 등록된다.(이게 맞나??)

클라이언트가 요청을 하게 되면 ServerSocketChannel은 셀렉터에 OP_ACCPET 키로 등록을 한다.
(채널의 이벤트에 따른 Selector에 키를 담는 로직들은 main Thread에 종속되어 처리되는 것이 아닌듯.)

메인스레드의 셀렉터는 무한히 도는 forLoop 안에서 선택된 키가 있는지 select()하며 선택된 키들을 Iterator로 가져오고, Iterator에 대해 foreach loop를 돌며 처리를 한다.

  • 서버 소켓의 논블록킹에대한 정리.
    스레드를 생성하지 않고도 연속적인 클라이언트의 요청을 받을 수 있다.
  • 요청별로 스레드를 생성하지 않고 하나의 메인스레드를 통해 순서적으로 요청이 처리되어진다. 스레드를 생성하지 않으므로 많은 리소스를 사용하지 않는다. …

흠.. 요청 별 처리로직의 블록킹은 어찌되는 건지 책을 더봐보자.

아래는 논블록킹 서버소켓의 샘플.

Written by

엘디는 사랑입니다.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store