우선 네티는 자바로 구현한 소켓 프로그래밍과 똑같다.
다만, 네티만의 추상화로 인해 자바 소켓 프로그래밍과 그 궤를 달리한다.
우선 위 사진을 보면 Client와 Server의 Inbound와 Outbound가 서로 반대방향인 것을 확인할 수 있다.
이는 본인을 기준으로 데이터가 들어오면 Inbound 데이터가 나가면 Outbound이다.
이게 굉장히 중요한데 이 한 문장을 얻기까지 꼬박 하루가 걸렸다.
spring-framework를 운용하고 내부에 다로 netty를 운용하여 spring으로부터 들어오는 요청은 netty 서버 내부에서 inbound로 처리되는 줄 알았다. 하지만 outboud로 처리된다.
Netty의 이벤트 모델에서 Inbound와 Outbound 이벤트는 네트워크 트래픽의 방향을 나타낸다.
Inbound 이벤트
는 네트워크에서 서버로 들어오는 데이터를 가리키며, 이는 주로 클라이언트 또는 다른 서버 등 외부 요청에 의해 발생한다.
예를 들어, 사용자가 웹 브라우저에서 요청을 보내면, 이 요청은 서버로 들어오는 Inbound 이벤트로 처리된다.
반면, Outbound 이벤트
는 서버에서 네트워크로 나가는 데이터를 가리키며, 이는 주로 서버의 응답 또는 서버의 내부 로직에 의해 발생한다.
예를 들어, 서버가 클라이언트에게 응답을 보내면, 이 응답은 네트워크로 나가는 Outbound 이벤트로 처리된다.
즉, @Service단의 비즈니스 로직에서 Netty 서버로 데이터를 보내는 경우, 이 데이터는 서버 내부에서 다른 부분(여기서는 Netty 서버)으로 이동하는 것이므로, 이는 "서버 내부에서 발생하는 이벤트"로 볼 수 있다는 것이다.
그리고 이 데이터는 최종적으로 네트워크를 통해 외부(클라이언트나 다른 서버 등)로 전송되는 것이 목적이므로, 이는 "서버에서 네트워크로 나가는 데이터"라고 할 수 있다.
즉, 서비스 로직이 처리 결과를 Netty 서버에 전달하고, 이 결과가 Netty 서버에서 클라이언트로 전송되는 이런 흐름 전체를 Outbound 이벤트로 보는 것이다.
Netty는 기본적으로 비동기 이벤트 기반의 네트워크 프로그래밍 프레임워크로서, TCP와 UDP, HTTP/2 같은 다양한 프로토콜을 지원하며, 고성능 및 고척도성을 가진 네트워크 애플리케이션을 구축하기 위한 기반 인프라를 제공한다.
따라서 Netty는 웹 서버, 프록시 서버, 채팅 서버, 게임 서버와 같은 다양한 유형의 네트워크 서비스를 구축하는데 사용될 수 있다.
그러나 Netty 자체는 웹 애플리케이션 개발에 필요한 많은 기능들 (예를 들어 데이터베이스 연결, ORM(Object-Relational Mapping), 템플릿 엔진, 인증 및 권한 관리, RESTful API 지원 등)
을 직접 제공하지는 않는다.
따라서 복잡한 웹 애플리케이션을 개발할 때는 Netty와 같은 네트워크 프레임워크와 Spring과 같은 백엔드 프레임워크를 함께 사용하는 경우가 많다.
이런 경우, Netty는 클라이언트와의 네트워크 통신을 담당하고, Spring은 비즈니스 로직 처리, 데이터베이스 연결 등의 역할을 수행한다.
실제로, Spring WebFlux는 Netty를 기본적으로 내장한 서버를 제공하며, 이를 통해 비동기 및 논블로킹 모델을 기반으로 한 웹 애플리케이션을 개발할 수 있다.
네티만이 갖고있는 개념이 있다.
우리가 흔히 아는 부트스트랩은 아마 웹사이트를 쉽게 만들 수 있게 도와주는 CSS, JS 프레임워크일 것이다.
하지만 네티에서의 부트스트랩은 네티로 작성한 네트워크 프로그램이 시작할 때 가장 먼저 수행되는 객체로서 하는일은 아래와 같다.
그럼 부트스트랩에서 설정할 수 있는 것들에는 무엇무엇이 있을까?
이벤트 핸들러를 상속받아서 구현한 구현체들이다. 자주 사용하는 이벤트 핸들러들을 미리 구현해둔 코덱 묶음은 io.netty.handler.codec
패키지에 있다.
대표적으로는 decoder, encoder가 있다.
주로 체널 파이프라인에 일부를 담당한다.
writeAndFlush
메서드로 채널에 데이터 기록
close
메서드로 채널의 연결을 종료시킴
프로그래머에 의한 이벤트 발생
채널 파이프라인에 등록된 이벤트 핸들러의 조회 및 동적 변경
예를들어 데이터 수신 이벤트 처리 메서드에서 오류가 발생했고 오류처리 공통로직이 exceptionCaught 이벤트 메서드에 작성되어 있다면, fireExceptionCaught 메서드를 호출할 수 있다.
채널 파이프라인으로 exceptionCaught 이벤트 전달.
이벤트 루프 : 이벤트를 실행하기 위한 무한루프 스레드
이벤트 큐에 이벤트를 등록하고 이벤트 루프가 큐에 접근하여 처리한다.
이벤트 루프가 다중 스레드이면 한 큐를 여러 스레드에서 공유해서 쓴다.
*데이터 수신 이벤트가 발생했을 때 이벤트루프가 이벤트를 처리하는 과정
1. 네티의 이벤트 루프가 채널 파이프라인에 등록된 이벤트 핸들러를 가져옴
2. 해당 핸들러에 데이터 수신 이벤트에 대한 메서드가 구현되어있다면 실행
3. 해당 메서드가 없다면 다음 핸들러 가져옴
4. 채널 파이프라인에 등록된 마지막 이벤트 핸들러까지 위 과정 반복
소켓 채널에서 발생한 이벤트를 처리하는 인터페이스
채널 파이프라인에 등록되어 파이프라인으로 들어오는 이벤트를 이벤트루프가 가로채어 알맞은 메서드를 수행한다
채널 파이프라인에 여러 개의 이벤트 핸들러가 등록되어 있을 때의 동작
1. 등록된 이벤트 핸들러가 없다면 무시된다.
2. 등록된 이벤트 핸들러가 한 개이면 해당 핸들러가 적용된다.
3. 등록된 이벤트 핸들러가 여러 개이면 가장 앞에 있는게 적용되고 뒤로 전달되지 않는다. (이게 중요!!)
4. 다음 이벤트 핸들러로 이벤트를 넘겨주는 방법은 channelHandlerContext.fireChannelRead 메서드 호출. 채널 파이프라인에 해당 이벤트를 발생시킨다.
네티는 소켓 채널에서 발생하는 이벤트를 '인바운드 이벤트'와 '아웃바운드 이벤트'로 추상화한다.
연결 상대방이 어떤 동작을 취했을 때 발생 (ex 채널 활성화, 데이터 수신 등)
네티는 인바운드 이벤트 핸들러를 ChannelInboundHandler 인터페이스로 제공한다.
channelRegistered
채널이 이벤트루프에 등록되었을 때 발생
새로운 채널이 생성되는 시점에 발생
서버에서는 서버 소켓 채널 생성시, 클라이언트 소켓 채널 생성시 발생
클라이언트 에서는 connect 메서드를 수행할 때 (클라이언트 소켓 채널 생성시) 발생
channelActive 이벤트
channelRegistered 이후에 발생
채널이 생성되고 이벤트 루프에 등록된 후, 네티 API 를 이용하여 채널 입출력을 수행할 상태가 되었음을 알려주는 이벤트
서버 또는 클라이언트가 상대방에 연결한 직후에 한번 수행할 작업을 처리하기에 적합
channelRead 이벤트
데이터가 수신되었음을 알려주는 이벤트
수신된 데이터는 ByteBuf 객체에 저장되어 있음
channelReadComplete 이벤트
데이터 수신이 완료되었음을 알려주는 이벤트
채널의 데이터를 다 읽어서 더 이상 데이터가 없을 때 발생
channelInActive 이벤트
채널이 비활성화 되었을 때 발생
이 이후에는 채널에 대한 입출력 작업을 수행할 수 없음
channelUnRegistered 이벤트
채널이 이벤트 루프에서 제거되었을 때 발생
이 이후에는 채널에서 발생한 이벤트를 처리할 수 없음
소켓 채널에서 발생한 이벤트 중 프로그래머가 요청한 동작에 해당하는 이벤트
채널 아웃바운드 이벤트를 처리하는 핸들러 구현을 위해 ChannelOutboundHandler 인터페이스를 사용한다.
이 인터페이스의 핸들러 메소드들은 ChannelHandlerContext 객체를 인수로 받는다.
bind 이벤트
서버 소켓채널이 클라이언트의 연결을 받아들이는 ip,port 정보 설정시 발생
connect 이벤트
클라이언트 소켓채널이 서버에 연결되었을 때 발생
disconnect 이벤트
클라이언트 소켓채널의 연결이 끊어졌을 때 발생
close 이벤트
클라이언트 소켓채널의 연결이 닫혔을 때
write 이벤트
소켓채널에 데이터가 기록되었을 때 발생
flush 이벤트
소켓채널에 대한 flush 메서드 호출시 발생