자바 네트워크 애플리케이션 프레임워크.
비동기 이벤트 기반 네트워크 응용프로그램 프레임워크
사용하는 이유
특징
이벤트를 정의하고 이벤트가 발생했을 떄 실행될 코드를 준비해둔다.
논 블로킹 소켓의 Selector를 사용한 I/O 이벤트 감지 및 처리도 이 종류 중 하나이다.
이벤트를 발생시키는 객체와 발생될 이벤트의 종류를 정의
네트워크 프로그램에서 이벤트 발생의 주체는 소켓이며 이벤트 종류는 소켓 연결, 데이터 송수신이다.
소켓 통신을 이용해서 클라이언트와 서버의 연결을 유지한다
netty에서는 소켓통신을 하기 때문에 IP, port 번호가 필요하다.
데이터를 송수신 할 때 사용되는 통로인 channelContextHandler 인터페이스 클래스 사용.
클라이언트와 서버간의 송수신은 bootstrap을 이용하여 연결이 수립된 뒤 부터 channelContextHandler 클래스를 이용하여 데이터를 송수신할 수 있음.
channelContextHandler 클래스에는 데이터가 오가는 Channel 클래스가 포함되어있는데 이 채널에 클래스에 데이터가 들어오는 인바운드, 데이터가 나가는 아웃바운드 설정을 할 수 있다.
bootstrap
: netty의 스레드를 생성하고, 소켓을 오픈하는 등 netty를 구동하기 위한 부트 스트래핑을 위해 사용하는 클래스
EventLoopGroup
: netty의 eventLoopGroup은 eventLoop들의 그룹이다. 여러개의 이벤트 루프는 하나의 그룹으로 모아질 수 있다. 같은 그룹에 속한 이벤트 루프들은 스레드와 같은 몇몇 리소스들을 공유하게 된다.
EventLoop
: netty의 eventLoop은 새로운 이벤트를 반복적으로 확인하는 루프이다. 예를 들어 soketChannel로부터 새로운 데이터가 들어오는 것 같은 이벤트를 매번 확인한다.
이벤트가 발생하면 적당한 이벤트 핸들러에 전달.
socketChannel
: netty의 소켓채널은 tcp 연결을 대표한다. 네트워크 프로그램에서 server나 clinet가 netty를 사용한다면 머신 사이에서 데이터를 전달하는 과정은 소켓 채널을 통해서 이루어진다.
socketChannel은 항상 같은 eventLoop에 의해 관리가 된다. 같은 eventLoop은 항상 같은 스레드에서 실행되기 때문에 socketChannel은 항상 같은 스레드에서 접근이 된다.
이 때문에 순서가 보장된다.
다라서 같은 소켓 채널에서 동시에 데이터가 읽히는 것에 대해서는 걱정하지 않아도 된다.
channelInitializer
: 네티의 channelInitializer는 socketChannel이 생성될 때 channelPipeline에 추가되는 특별한 channelHandler다. 이 객체는 socketChannel을 초기화하는 역할
socketChannel이 초기화되면 channelPipeline에서 channelInitializer가 제거된다.
channelPipeline
: 각각의 socketChannel은 channelPipeline을 가지고 있다.
채널파이프라인은 channelHandler 인스턴스의 리스트이다.
eventLoop가 데이터를 socketChannel에서 읽으면 데이터는 파이프라인에 있는 첫번째 채널 핸들러에게 넘겨진다. 첫 번째 핸들러는 넘겨받은 데이터를 처리하고 필요한 경우 파이프라인의 다음 핸들러로 데이터를 넘길 수 있다
데이터를 socketChannel로 쓰는 경우도 마찬가지로 channelPipeline을 타게되며 핸들러들을 거친다음 socketChannel로 쓰여지게 된다.
네트워크 연결을 나타내며 NIO의 SelectableChannel을 기반으로 구현되어있다.
채널을 사용하여 네트워크 연결을 설정하고 데이터를 읽고 쓰고 이벤트를 수신하고 속성을 설정할 수 있다.
제공 기능
주요 메서드
ChannelOption (netty) : option - 서버 소켓 채널의 소켓 옵션 설정
: 소캣의 동작 방식 지정, 소켓의 송수 신 패킷 크기 설정
TCP_NODELAY : 데이터 송수신에 네이글 알고리즘 비활 성화 여부 지정
SO_KEEPALIVE : 운영체제에서 지정된 시간에 한번씩 keepalive 패킷을 상대 방에게 전송
SO_BACKLOG : 동시에 수용 가능한 소켓 연결 요청수
TCP_NODELAY: Nagle 알고리즘 비활성화 여부 설정: 네트워크 통신에서 발생하는 작은 패킷들을 하나의 큰 패킷으로 묶어서 전송함으로써 효율성을 향상
SO_SNDBUF: 커널 송신 버퍼 크기
SO_RCVBUF: 커널 수신 버퍼 크기
SO_REUSEADDR: TIME_WAIT 상태의 포트에도 bind 가능해짐
SO_LINGER: 소켓을 닫을 때 송신 버퍼에 남은 데이터 전송 대기 시간
Netty의 핵심 요소
Netty의 I/O 이벤트를 처리하는 인터페이스
ChannelInboundHandlerAdapter
ChannelOutboundHandlerAdapter
ChannelHandler 는 ChannelHandlerContext 를 통해
다음 ChannelHandler 에게 이벤트를 넘기거나,
동적으로 ChannelPipeline 를 변경할 수 있음
각 이벤트 핸들러당 하나씩 생성됩니다. 이벤트 핸들러는 Netty의 파이프라인을 통해 연결된 Channel로 들어오는 이벤트를 처리하고, ChannelHandlerContext를 통해 해당 Channel과 관련된 작업을 수행합니다.
ChannelHandlerContext의 인스턴스는 Netty의 파이프라인을 통해 자동으로 생성되며, 이벤트 핸들러가 파이프라인에 추가될 때마다 생성됩니다. 각 이벤트 핸들러에 대해 ChannelHandlerContext는 해당 핸들러와 관련된 Channel 및 파이프라인 정보를 갖고 있습니다.
네티는 해제되지 않은 리소스를 WARN 수준 로그 메시지로 로깅하므로 코드에 문제가 되는 인스턴스가 있으면 쉽게 발견할 수 있다
그러나 이렇게 매번 리소스를 관리하기 번고웁기 때문에 해당 핸드퍼를 사용하면 쉽게 리소스를 관리할 수 있다.
리소스를 자동으로 해제하므로 메시지의 참조도 무효화된다. 즉 메시지의 참조를 저장해 나중에 사용하려고 하면 안된다.
메시지가 ChannelRead0()에서 소비되면 자동으로 메시지를 해제
: ChannelHandler는 들어온 이벤트를 처리하는 ChannelInboundHandler와 나가는 이벤트를 처리하는 ChannelOutboundHandler가 있고, ChannelDuplexHandler는 나가는것과 들어오는것 이벤트를 두개다 처리하는 핸들러
채널의 이벤트를 처리하는 담당
채널에 연결된 핸들러의 목록을 포함하고 핸들러는 채널이 발생하는 이벤트를 처리한다
제공 기능
주요 메서드
네티에서 서버를 생성하고 시작하는데 사용되는 클래스로 서버를 생성하고 시작할 때 지정된 포트에서 서버를 바인드하거나 지정된 주소로 연결할 수 있다.
또한 서버에 핸드러를 추가하고 속성을 설정할 수 있다.
handler
and childHandler
methods in Netty's ServerBootstrap
class is that the handler
method is used to configure the pipeline for the bootstrap itself, while the childHandler
method is used to configure the pipeline for each individual client connection that is accepted by the server.In other words, the handler
method is used to configure the handlers that will be executed for all events that occur on the bootstrap itself, such as when the bootstrap is started or when it encounters an error. The childHandler
method, on the other hand, is used to configure the handlers that will be executed for all events that occur on each individual client connection, such as when a message is received from the client or when the connection is closed.
Here is an example of how the handler
and childHandler
methods can be used to configure a Netty server:
ServerBootstrap bootstrap = new ServerBootstrap();
// Configure the pipeline for the bootstrap
bootstrap.handler(new LoggingHandler());
// Configure the pipeline for each client connection
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// Add a logging handler to the pipeline
ch.pipeline().addLast(new LoggingHandler());
// Add an echo handler to the pipeline
ch.pipeline().addLast(new EchoHandler());
}
});
In this example, the handler
method is used to add a LoggingHandler
to the pipeline for the bootstrap. This handler will log all events that occur on the bootstrap, such as when the bootstrap is started or when it encounters an error. The childHandler
method is then used to add a ChannelInitializer
to the pipeline for each client connection. This ChannelInitializer
will add a LoggingHandler
and an EchoHandler
to the pipeline for each client connection. The LoggingHandler
will log all events that occur on the client connection, and the EchoHandler
will echo back any messages that it receives from the client.
I hope this helps! Let me know if you have any other questions.
: 채널이 특정 시간동안 활동이 없을 때 발생하는 이벤트로 이벤트는 채널이 연결되어 있지만 데이터가 수신되지 않거나 전송되지 않을 때 발생
BOSS
WORKER
Channel은 ChannelPipeline으로 메시지를 전달한다. ChannelPipeline은 기본적으로 TailContext와 HeadContext를 가진다. Pipeline의 시작과 끝이라 할 수 있다. Tail과 Head 사이에는 사용자가 등록한 ChannelHandlerContext가 체인 구조로 연결되고, 전달된 메시지가 체인을 따라 Outbound 방향으로 흘러간다.
비동기 작업의 결과를 나타내는 개념으로 비동기 작업이 완료되었는지 여부를 체크하고 비동기 작업의 결과를 가져올 수 있다
제공 기능
주요 메서드
closeFuture = channelFuture.channel().closeFuture();
closeFuture()
: 채널의 CloseFuture를 얻고 완료 될때 까지 현재 스레드를 블로킹한다.
(클라이언트)
1. bootstrap 생성
2. eventLoopGroup 생성
3. bootstrap 체이닝을 통한 그룹, 옵션, 핸들러 설정
4. bootstrap.connect(ip, port) : 연결 부분
하나의 부트스트랩에 하나의 이벤트 처리 스레드를 설정한다.
수신된 데이터는 inboundHandler를 상속받은 클래스에서 decode() 동작
decode() 메소드를 동작시킨 뒤 나온 데이터는 channelRead()메소드 동작
참고
- https://velog.io/@monami/Netty#%EB%84%A4%ED%8B%B0%EC%97%90%EC%84%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9D%B4%EB%8F%99%EC%9D%98-%EB%B0%A9%ED%96%A5%EC%84%B1
- https://deveric.tistory.com/99
- https://i-hope9.github.io/2020/12/08/SpringBoot-Netty-1-Background.html
- https://altongmon.tistory.com/501
- https://javafactory.tistory.com/1525
- https://okky.kr/questions/228975
- https://techblog.woowahan.com/2681/
- https://velog.io/@joosing/netty-tx-message-flow
- https://parkhyeokjin.github.io/netty/2019/12/29/netty-chap2.html