Java Old I/O
- Java의 입출력은 Stream 기반으로 이뤄지고, 동기적으로 처리가 된다.
- 가장 단순한 서버--클라이언트의 연결을 살펴보면 서버는 클라이언트가 연결될 때까지 차단되고, 클라이언트가 요청이오면 해당 쓰레드는 클라이언트와 연결되어 추가 연결요청을 응답할 수 없음.
다중 클라이언트의 요청을 연결하는 방법
멀티 프로세스 기반 서버
- 단순하게 요청이 올 때 마다, 서버 프로세스를 생성해서 서비스를 제공하는 방식이다.
- 쓰레드도 아니고, 프로세스를 계속해서 생성한다는것은 굉장히 무거운 작업이고, CPU 오버헤드가 발생한다. -> 비효율
멀티 스레드 기반 서버 구성
- 하나의 프로세스 내에 2개 이상의 스레드를 생성.
- 연결은 하나의 스레드가 담당하고, 실제 작업은 다른 스레드를 생성하여 위임하는 방식.
- 이전 방식보단 말이 된다.
요청당 스레드 모델

- 클라이언트의 요청마다 쓰레드를 생성하여 작업을 위임하는 방식
- 문제점
- 쓰레드가 무한정 커지면 쓰레드가 소유하는 스택메모리 또한 누적뇌어, OOM(Out Of Memory) 문제 발생 가능.
- 쓰레드의 컨텍스트 스위치 비용 또한 증가하여 오히려 성능 감소 가능성 존재.
- 요청을 받는 accept()를 수행하는 쓰레드는 결국 하나다. 즉 병목 발생 가능
쓰레드 풀링 모델
- 미리 쓰레드풀을 생성해 쓰레드의 개수를 정해둔다.
- 문제점
- 쓰레드의 메모리 할당 문제는 해결되지만, 쓰레드의 개수가 정해져있어서 동시접속자 수가 쓰레드의 개수에 의존적이다.
Java nio의 등장 배경
- 기존의 java i/O 방식은 스레드가 I/O를 수행할 때 마다 Block된다.
- 이유는, 클라이언트와 서버 각각 서로의 데이터 송/수신을 기다리고 있기 때문이다.
- 따라서, 하나의 쓰레드가 다른 클라이언트의 입출력을 처리할 수 없게 됨.
Non-Blocking
- 블로킹 모드의 동작방식은 많은 동접자를 수용하기 어렵다는 문제점이 있다.
- 쓰레드 하나가 다수의 클라이언트의 요청을 수행한다면 효율적일것이다. -> 이를 입출력 다중화라고 한다.

Channel
- Non blocking을 구현하기 위해서, 양방향 입출력이 가능한 채널을 사용한다.
- 버퍼를 사용해 읽거나 쓴다.
ByteBuffer
Buffer:데이터를 채널로 전송하거나 채널에서 데이터를 수신할 때 사용되는 클래스
ByteBuffer: 채널에서 데이터를 전송할 때 사용함. limit, capacity, position 같은 옵션을 지정할 수 있다.
Selector

- java nio의 핵심이다.
- 다수의 채널을 연결해 입출력 수행할 수 있게 해주는 클래스
- 각 채널에서 발생하는 연결,입출력을 이벤트 기반으로 처리함.
- 셀렉터의 이벤트와 이벤트 핸들러를 설정해두고, 클라이언트의 요청에 따라 발생하는 이벤트를 처리하는 형식으로 NonBlocking I/O를 지원함.
장단점
- 하나의 쓰레드로 둘 이상의 요청을 처리할 수 있다.
- I/O 바운드를 줄여주지만, CPU 바운드를 줄여주진 않는다. 오히려 하나의 쓰레드에서 작업의 교체가 많이 발생해 CPU의 작업량은 더 올라간다.
- CPU를 많이 사용하는 작업의 경우 쓰레드 풀링을 사용해서 처리하는 방법이 더 효율적일 수 있다.
Netty
- Netty가 없다면, 포트 바인딩, 이벤트 핸들러, 파이프라인등 많은 코드를 작성해야하는 어려움 존재.
- 즉, low-level 처리를 해주어야하고, 이를 구현할 지식이 수반된다.
Netty는 비동기, 이벤트 기반의 네트워크 애플리에키션 프레임워크이다.
- 추상화된 api를 제공하여 빠르고 쉽게 구현이 가능하다.
- 이벤트 기반 프로그래밍이 가능하다.
- java.nio와 다른점은 데이터 송/수신 로직과 예외처리 로직을 직접 작성해야한다.

- Netty를 사용하면 이벤트에대한 핸들러를 제공한다.
Event Handler API
package io.netty.channel;
public interface ChannelInboundHandler extends ChannelHandler {
void channelRead(ChannelHandlerContext var1, Object var2) throws Exception;
void exceptionCaught(ChannelHandlerContext var1, Throwable var2) throws Exception;
}
- 클라이언트가 보낸 데이터를 서버가 수신할 때 동작하는 이벤트 핸들러이다.
package io.netty.channel;
import java.net.SocketAddress;
public interface ChannelOutboundHandler extends ChannelHandler {
void write(ChannelHandlerContext var1, Object var2, ChannelPromise var3) throws Exception;
}
- 클라이언트에게 데이터를 송신(응답)할 때, 동작하는 이벤트 핸들러(객체,클래스)