Netty 시작하기 (4)

풍부한 코덱과 웹소켓

김대현
@hatemogi

지난 시간의 ChatServer.java


public final class ChatServer {
  public static void main(String[] args) throws Exception {
    NettyStartupUtil.runServer(8030, new ChannelInitializer<SocketChannel>() {
      @Override
      protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline()
          .addLast(new LineBasedFrameDecoder(1024, true, true))
          .addLast(new StringDecoder(CharsetUtil.UTF_8),
                   new StringEncoder(CharsetUtil.UTF_8))
          .addLast(new ChatMessageCodec(),
                   new LoggingHandler(LogLevel.INFO))
          .addLast(new ChatServerHandler());
      }
    });
  }
}
						

src/nettystartup/h4/WebChatServer.java


public class WebChatServer {
    static String index = System.getProperty("user.dir") + "/res/h4/index.html";

    public static void main(String[] args) throws Exception {
        NettyStartupUtil.runServer(8040, new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) {
                ChannelPipeline p = ch.pipeline();
                p.addLast(new HttpServerCodec());
                p.addLast(new HttpObjectAggregator(65536));
                p.addLast(new WebSocketHandshakeHandler("/chat", new WebChatHandler()));
                p.addLast(new HttpStaticFileHandler("/", index));
                // TODO: [실습4-1] 실습3-2와 마찬가지로 404 응답을 처리하게 합니다.
            }
        });
    }
}
						

WebSocketHandshakeHandler.java


class WebSocketHandshakeHandler extends S..C..I.Handler<FullHttpRequest> {
    protected void channelRead0(C..H..Context ctx, FullHttpRequest req) throws Exception {
        ...  handshakeWebSocket(ctx, req); ...
    }

    private void handshakeWebSocket(C..H..Context ctx, FullHttpRequest req) {
    	  ...
        h.handshake(ctx.channel(), req).addListener((ChannelFuture f) -> {
            // replace the handler when done handshaking
            ChannelPipeline p = f.channel().pipeline();
            p.replace(WebSocketHandshakeHandler.class, "wsHandler", wsHandler);
        }
    }
}
						

src/nettystartup/h4/WebChatHandler.java


class WebChatHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // TODO: [실습4-2] 파이프라인에 코덱과 핸들러를 추가해서 WebSocket과 ChatServerHandler를 연결합니다.
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
        ... TextWebSocketFrame만 걸러서 다음 핸들러에 넘기는 코드 ...
        ctx.fireChannelRead(frame.retain());
    }
}
						

src/nettystartup/h4/WebSocketChatCodec.java


class WebSocketChatCodec extends
        MessageToMessageCodec<TextWebSocketFrame, ChatMessage> {
    @Override
    protected void encode(C..H..Context ctx, ChatMessage msg, List<Object> out) throws E.. {
        out.add(new TextWebSocketFrame(msg.toString()));
    }

    @Override
    protected void decode(C..H..Context ctx, TextWebSocketFrame msg, List<Object> out) throws E.. {
        out.add(ChatMessage.parse(msg.text()));
    }
}