netty

이번엔 이벤트 핸들러에 대해 알아보자
ChannelInboundHandlerAdapter 클래스는 ChannelInboundHandler 인터페이스를 사용한 어댑터이다.
실질적인 구현에 대한 로직은 없다.
아래는 ChannelInboundHandler 인터페이스의 내용이다.

    void channelRegistered(ChannelHandlerContext ctx) throws Exception;

    void channelUnregistered(ChannelHandlerContext ctx) throws Exception;

    void channelActive(ChannelHandlerContext ctx) throws Exception;

    void channelInactive(ChannelHandlerContext ctx) throws Exception;

    void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;

    void channelReadComplete(ChannelHandlerContext ctx) throws Exception;

    void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;

    void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;

    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

자주쓰는 메소드들을 살펴보자.

channelRegistered

채널이 이벤트 루프에 등록되었을 때 발생한다.
이벤트 루프는 네티가 이베트를 실행하는 스레드로써 부트 스트랩에 설정한 이벤트 루프다.

channelActive

channelRegistered 다음에 바로 실행 되는 메소드다. 이벤트 루프에 등록된 이후에 네티 API를 사용하여 채널 입출력을 수행할 상태다.
다음과 같은 작업을 할 수 있다.
클라이언트 연결 개수를 셀 때
최초 연결 메시지를 보낼 때
연결된 상태에 대한 작업이 필요 할때

channelRead

channelRead 는 제일 빈도가 높은 메소드이다.
데이터가 수신 되었을 때 알려주는 메소드이다. 수신된 데이터는 네티의 ByteBuf 객체에 저장되어 있으며 두번째 인자 msg를 통해 접근가능하다. 실질적인 비지니스 로직도 여기에서 이뤄질거 같다.

channelReadComplete

데이터 수신이 완료되었을음 알려준다.
간단하게 예를 들어 보자. 클라리언트가 서버로 ‘A’, ‘B’, ‘C’ 라는 데이터를 순차적으로 전송했다고 하자. 이때 서버에서는 channelRead 이벤트가 발생하는데 이때 msg 객체에 수신된 데이터가 ‘ABC’라면 다음으로 발생하는 이벤트는 channelReadComplete다. 반대로 msg객체에 수신된 데이터가 ‘A’라면 다음으로 발생하는 이벤트는 channelRead이다. 즉 데이터를 다 읽어 없을때 발생하는 이벤트가 바로 channelReadComplete이다.

channelInactive

channelActive와 반대로 채널이 비활성화 되었을 때 발생한다. 해당 이벤트가 발생한 이후에는 채널에 해당 입출력 작업을 수행 못한다.

channelUnregistered

channelRegistered의 이벤트와 반대로 채널이 이벤트 루프에서 제거 되었을 때 발생한다. 이거 또한 채널에 입출력 작업을 수행하지 못한다.

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
  System.out.println("channelActive");
}

@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  System.out.println("channelInactive");
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  System.out.println("channelRead");
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  System.out.println("channelReadComplete");
}

@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
  System.out.println("channelRegistered");
}

@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
  System.out.println("channelUnregistered");
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  cause.printStackTrace();
  ctx.close();
}

순서는 즉 이렇다.
클라이언트가 접속 했을 경우 발생
channelRegistered
channelActive
위에 두개가 출력된다.

클라이언트가 메시지를 보낼 때 발생
channelRead

모든 메시지를 다 읽고 없을 때 발생
channelReadComplete

클라이언트가 접속이 끊어 졌을 때
channelInactive
channelUnregistered

이러식으로 이벤트 핸들러가 발생한다.