2019년 1월 2일 수요일

[Netty] IdleStateHandler - Idle 상태를 감지하는 핸들러.

https://netty.io/4.0/api/io/netty/handler/timeout/IdleStateHandler.html

IdleStateHandler는 특정 시간 동안 read, write, 또는 read/write 동작이 없을 때 이를 체크해 사용자에게 알려주는 역할을 수행한다. IdleStateHandler는 Inbound와 Outbound를 모두 처리하는 ChannelDuplexHandler를 상속받아 구현되어 있다.

보통 인스턴스를 만드는데 사용하는 생성자는 아래와 같다.
IdleStateHandler(int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdletimeSeconds)

앞서 적혀있듯이 IdleStateHandler는 read에 대한 idle 감지, write에 대한 감지, read/write에 대한 idle 감지의 3가지 타입을 제공해주고 있다. 내부적으로는 one-shot 타이머 쓰레드가 반복적으로 송수신 메시지가 있는지 없는지를 확인해주는 방식이므로 불필요한 자원을 낭비하지 않으려면 필요없는 타입의 timeout 파라미터에 '0' 값을 전달해 해당 기능을 끄는게 좋다.

마지막으로 사용자는 IdleStateHandler가 통지하는 이벤트를 받아 처리하기 위해 ChannelDuplexHandler를 상속받아 userEventTriggered 메서드를 구현해야 한다.

온라인 API 문서엔 다음과 같은 예제가 있다.


// 60초 동안 수신하는 메시지가 없으면 MyHandler에 의해 클라이언트와의 연결을 끊는다.
// 30초 동안 송신하는 메시지가 없으면 MyHandler가 핑 메시지를 클라이언트로 전송한다.
public class MyChannelInitializer extends ChannelInitializer<Channel> {
    @Override
    public void initChannel(Channel channel) {
        channel.pipeline().addLast("idleStateHandler", new IdleStateHandler(60, 30, 0));
        channel.pipeline().addLast("myHandler", new MyHandler());
    }
}

public class MyHandler extends ChannelDuplexHandler {
    // 사용자는 userEventTriggered에서 이벤트의 상태를 읽어 필요한 동작을 지정해주면 된다.
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                ctx.close();
            } else if (e.state() == IdleState.WRITER_IDLE) {
                ctx.writeAndFlush(new PingMessage());
            }
        }
    }
}

ServerBootstrap bootstrap = ...;
...
bootstrap.childHandler(new MyChannelInitializer());
...

댓글 2개: