아래 예제에선 채널 파이프라인에 ObjectEncoder와 ObjectDecoder를 지정해 주었다. ObjectEncoder는 Java 객체를 ByteBuf로 serialize 하는 역할을 수행하고, ObjectDecoder는 수신한 ByteBuf를 Java 객체로 deserialize 해준다.
싱글턴으로 XXXXClient를 구현하고 핸들러에 메시지를 전송할 수 있는 메서드를 열어두면 간단하게 소켓 클라이언트를 구현할 수 있다. Handler로 전달된 참조형 객체(ByteBuf)의 해제는 핸들러의 책임인 것으로 알고 있다. 읽는 쪽의 어딘가에서 ReferenceCountUtil.release() 해주어야 한다. 메시지를 쓰기 위해 필요한 ChannelHandlerContext는 channelActive 시점에 셋 해주면 될 것이다.
public class XXXXClient { private EventLoopGroup workerGroup = new NioEventLoopGroup(); private XXXXHandler handler = new XXXXHandler(...); // Singleton. public void start(...) { new Thread(() -> { try { Bootstrap b = new Bootstrap(); ChannelFuture f = b.group(workerGroup) .channel(NioSocketChannel.class) .option(...) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( new ObjectEncoder(), new ObjectDecoder(ClassResolvers.cacheDisabled(null)), handler); } }) .connect(ip, port).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { // ... } finally { workerGroup.shutdownGracefully(); } }).start(); } public void stop() { workerGroup.shutdownGracefully(); } public void sendMessage(Object msg) { handler.sendMessage(msg); } } public class XXXXHandler extends ChannelInboundHandlerAdapter { private ChannelHandlerContext context; public void channelActive(...) { super.channelActive(ctx); this.context = ctx; } public void channelRead(...) { if (msg instanceof YYYY) { ... } ReferenceCountUtil.release(msg); } public void channelReadComplete(...) { ctx.flush(); } public void sendMessage(Object msg) { if (context != null && context.channel().isWritable()) { context.writeAndFlush(msg); } } }
동작은 하는데 이렇게 하는게 맞는진 잘 모르겠다. :(
댓글 없음:
댓글 쓰기