기존 C/S 통신을 WebSocket 통신으로 변경하려고 합니다.

214 views
Skip to first unread message

미세먼지

unread,
Aug 4, 2021, 7:50:28 AM8/4/21
to Netty Korean User Group
안녕하세요. 처음 글부터 복잡해서 죄송합니다.
Netty는 [자바 네트워크 소녀 Netty] 책으로 입문했지만 WebSocket 쪽은 다루지 않아서 몇주째 시행착오를 되풀이하고 있습니다. 더 이상은 Netty 소스를 봐서도 잘 파악되지 않아 도움을 부탁드립니다.
기존 C/S 통신에서는 Java VO를 Json을 이용해서 Encode/Decode 했습니다.
기존 C/S 통신 관련 소스입니다.
우선 부트스트랩 관련 함수입니다 :
  private ChannelFuture bindServerBootstrap(final ServerBootstrap sb, final EventLoopGroup parentGroup,
          final EventLoopGroup childGroup, final int timeOut, final int port) throws Exception {
    sb.group(parentGroup, childGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
            .childOption(ChannelOption.SO_KEEPALIVE, true).handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
              @Override
              protected void initChannel(SocketChannel sc) throws Exception {
                ChannelPipeline cp = sc.pipeline();
                cp.addLast("idleStateHandler_1", new IdleStateHandler(0, timeOut, timeOut, TimeUnit.SECONDS));
                cp.addLast("idleStateHandler_2", new NettyIdleStateHandler());
                cp.addLast("encoder", new JsonObjectEncoder());
                cp.addLast("decoder", new JsonObjectDecoder());
                cp.addLast("inbound_1", heartBeatHandler);
                cp.addLast("inbound_2", loginHandler);
                cp.addLast("inbound_3", requestHandler);
              }
            });
    final ChannelFuture cf = sb.bind(port);
    final Channelfuture cfSync = cf.sync();
    final io.netty.channel.Channel ch = cfSync.channel();
    final ChannelFuture chClose = ch.closeFuture();
    return chCloseFuture;
  }
여기서 JsonObjectEncoder/Decoder는 
Java VO <-> Class Name | Json String 으로 Encode/Decode하도록 되어 있고요.
(다른 분이 개발하신 것을 물려받았습니다.)
그래서 loginHandler 등 Channel Inbound Handler (모두 ChannelInboundHandlerAdapter 상속) 들에서는 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception 메소드의 msg 인자로 Java VO 가 옵니다.

이번에 C/S 대신 클라이언트만 웹으로 바꾸면서 WebSocket 기반으로 통신을 변경하려고 하는데요.
일단 부트스트랩쪽 함수를 이렇게 바꿨습니다 :
  private ChannelFuture bindServerBootstrapWS(final ServerBootstrap sb, final EventLoopGroup parentGroup,
          final EventLoopGroup childGroup, final int timeOut, final int port) throws Exception {
    sb.group(parentGroup, childGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
            .childOption(ChannelOption.SO_KEEPALIVE, true).handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
              @Override
              protected void initChannel(SocketChannel sc) throws Exception {
                ChannelPipeline cp = sc.pipeline();
                //  cp.addLast("codec", new HttpServerCodec()); // HttpClientCodec과 차이가 무엇인지
                cp.addLast("decoder", new JsonHttpRequestDecoder());
                cp.addLast("aggregator", new HttpObjectAggregator(64*1024));
                cp.addLast("encoder", new JsonHttpResponseEncoder());
                cp.addLast("chunked", new ChunkedWriteHandler());
                cp.addLast("decompressor", new HttpContentDecompressor());
                cp.addLast("websocket", new WebSocketServerProtocolHandler("/ws"));
                cp.addLast("inbound_1", testHandler); // idleHandler는 일단 제외했습니다
              }
            });
    final ChannelFuture cf = sb.bind(port);
    final Channelfuture cfSync = cf.sync();
    final io.netty.channel.Channel ch = cfSync.channel();
    final ChannelFuture chClose = ch.closeFuture();
    return chCloseFuture;
  }
JsonHttpRequestDecoder / JsonHttpResponseEncoder 는 각각 HttpRequestDecoder / HttpResponseEncoder 를 상속받아서 만든 클래스입니다.
이렇게 해놓고 보니 testHandler의 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception 메소드의 msg 인자로 TextWebSocketFrame 이 오더라고요.
testHandler (NettyTestHandler 클래스) 에서 Echo 를 보내게 해서 Web Broswer에서 제대로 나오는 것까지는 확인을 했는데요.
실제로 메시지는 Java VO -> Class Name | Json String 로 만들어서 보낼 것이라서, 기존의 JsonObjectEncoder/Decoder 처럼 JsonHttpRequestDecoder / JsonHttpResponseEncoder 에서 Class Name과 Json 까지 처리하려고 했습니다.
그런데 이게 HttpRequestDecoder / HttpResponseEncoder 를 상속받아서는 그렇게 구현을 할 수가 없는 것 같아, 방법을 문의드립니다.
기존 C/S의 JsonObjectDecoder는 LengthFieldBasedFrameDecoder 를 상속받고 
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception 메소드에서 Java VO를 리턴하면 이것이 그대로 Inbound Handler의 channelRead 인자로 전달되었는데요.
WebSocket 쪽에서는 JsonHttpRequestDecoder 가 HttpRequestDecoder 를 상속받아봤더니, decode 메소드 자체가 protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception 로 되어 있어서, 여기서 Java VO를 만들어내도 Inbound Handler에 전달할 방법을 모르겠더군요.

말이 길어져서 죄송합니다.
아무튼 WebSocket 통신으로 변경한 후에도 
메시지는 Class Name | Json String 포맷으로 유지하고,
Channel Inbound Handler에서는 msg를 Java VO 형태로 받게 하는게 목적입니다.
그런데 Decoder/Encoder를 HttpRequestDecoder / HttpResponseEncoder 를 상속받아서는 그렇게 개발할 수가 없는 것 같아서, 방법을 문의드립니다.

미리 감사드립니다.
JsonHttpRequestDecoder.java
NettyNRemoteServer.java
NettyTestHandler.java
NettyLoginHandler.java
JsonObjectDecoder.java
Reply all
Reply to author
Forward
0 new messages