4

I have a Tcp client that connect to a old mainframe (52 years) that send and receive request and response from it.

Here is core connection part of the my client ,

public class SimpleConnector {

    private String carrier;
    private SocketChannel socketChannel;
    public static final byte END_OF_MESSAGE_BYTE = (byte) 0x2b;

    public SimpleConnector(String carrier, InetSocketAddress inetSocketAddress) throws IOException {
        this.carrier = this.carrier;
        socketChannel = SocketChannel.open();
        socketChannel.socket().connect(inetSocketAddress, 30000);
    }

    public void shutDown() throws IOException {
        this.socketChannel.close();
    }
    //Send Request
    public String sendRequest(String request) throws Exception {
            final CharsetEncoder charsetEncoder = Charset.forName("ISO-8859-1").newEncoder();
            int requestLength = 12 + request.length() + 1;
            ByteBuffer buffer = ByteBuffer.allocate(requestLength);
            buffer.order(ByteOrder.BIG_ENDIAN);
            buffer.putInt(requestLength);
            buffer.put(charsetEncoder.encode(CharBuffer.wrap(carrier)));
            buffer.put(charsetEncoder.encode(CharBuffer.wrap(request)));
            buffer.put(END_OF_MESSAGE_BYTE);
            buffer.flip();
            socketChannel.write(buffer);
            return readResponse();

    }
    //Read Response
    protected String readResponse() throws Exception {
            CharsetDecoder charsetDecoder = Charset.forName("ISO-8859-1").newDecoder();
            int responseHeaderLength = 12;
            ByteBuffer responseHeaderBuf = ByteBuffer.allocate(responseHeaderLength);
            responseHeaderBuf.order(ByteOrder.BIG_ENDIAN);
            int bytesRead = 0;
            do {
                bytesRead = socketChannel.read(responseHeaderBuf);
            } while (bytesRead!=-1 && responseHeaderBuf.position()<responseHeaderLength);

            if (bytesRead==-1) {
                throw new IOException(carrier + " : Remote connection closed unexpectedly");
            }
            responseHeaderBuf.flip();
            int lengthField = responseHeaderBuf.getInt();
            int responseLength = lengthField - responseHeaderLength;
            responseHeaderBuf.clear();
            ByteBuffer responseBuf = ByteBuffer.allocate(responseLength);
            bytesRead = socketChannel.read(responseBuf);
            if (bytesRead>responseBuf.limit() || bytesRead ==-1) {
                throw new IOException(carrier + " : Remote connection closed unexpectedly");
            }
            responseBuf.flip();
            if (responseBuf.get(responseBuf.limit()-1)==END_OF_MESSAGE_BYTE) {
                responseBuf.limit(responseBuf.limit()-1);
            }
            responseBuf.clear();
            String response = charsetDecoder.decode(responseBuf).toString();
            return response;

    }

    public static void main(String[] args) throws Exception{
        SimpleConnector simpleConnector = new SimpleConnector("carrier",new InetSocketAddress("localhost",9999));
        String response=simpleConnector.sendRequest("Request");
        System.out.println(response);
    }
}

I'm trying to rewrite the following piece using Netty. By using following tutorial as reference.

The problem I'm facing is I was able to connect to server but couldn't read or write from it . I'm using a ChannelInboundHandlerAdapter to do the read and write operations.

Here is my Netty Client

public class NettyClient {
    int port;
    Channel channel;
    EventLoopGroup workGroup = new NioEventLoopGroup();

    public NettyClient(int port){
        this.port = port;
    }

    public ChannelFuture connectLoop() throws Exception {
        try{
            Bootstrap b = new Bootstrap();
            b.group(workGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new NettyClientHandler());
                }
            }); 
            ChannelFuture channelFuture = b.connect("remote-ip", this.port).sync();
            this.channel = channelFuture.channel();

            return channelFuture;
        }finally{
        }
    }
    public void shutdown(){
        workGroup.shutdownGracefully();
    }

    public static void main(String[] args) throws Exception{

        try {
            NettyClient nettyClient = new NettyClient(12000);
            ChannelFuture channelFuture = nettyClient.connectLoop();
            System.out.println("Sleep 2sec");
            Thread.sleep(2000);
            String command ="username";
            final Charset charset = Charset.forName("ISO-8859-1");
            int length = 13 + command.length();
            if (channelFuture.isSuccess()) {
                ByteBuf byteBuf = Unpooled.buffer(1024);
                byteBuf.writeInt(length);
                byteBuf.writeCharSequence("Some Info",charset);
                byteBuf.writeCharSequence(command,charset);
               channelFuture.channel().writeAndFlush(byteBuf).addListener(new ListenerImpl());

            }
        }
        catch(Exception e){
            System.out.println(e.getMessage());
            System.out.println("Try Starting Server First !!");
        }
        finally {
        }
    }
private static final class ListenerImpl implements ChannelFutureListener{

    public void operationComplete(ChannelFuture channelFuture) throws Exception {
        if (channelFuture.isSuccess()){
            System.out.println("Success"); //I can see success in Listener after write, but couldn't read response

        }else {
            System.out.println("Failed");
        }
    }
}
}

Handler

public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("NettyClientHandler : channelRead" );
        ByteBuf byteBuf = (ByteBuf) msg;
        String message = byteBuf.toString(Charset.defaultCharset());
        System.out.println("Received Message : " + message);
    }

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

I Initially thought netty will work only with netty servers.But this answer clear my doubt about that

Does a Netty client work with a netty server only?

Can some one guide me, what I'm doing wrong ???

edwin
  • 7,985
  • 10
  • 51
  • 82
  • Can you please provide details of the exception that you are getting. – SpinSage Dec 18 '18 at 14:29
  • I used the classed mentioned in client in the tutorial of 'baeldung'.Not getting any exception my Response decoder is not triggering for read – edwin Dec 18 '18 at 14:53
  • Hard to say without seeing the full code but I suspect the order of how you put the handlers in the pipeline is the problem. Can you exchange the client handler and decoder so the decoder is "in front" of the client handler ? – Norman Maurer Dec 18 '18 at 16:47
  • @NormanMaurer tried that ,not working i updated the code – edwin Dec 18 '18 at 17:02
  • Hi @NormanMaurer I updated the client code – edwin Dec 20 '18 at 11:20

1 Answers1

2

I think the problem is with your ClientHandler. you should writeAndFlush() in channelActive method invoked when a connection has been established between the tcp server and client. Please use the below updated code and see whether it fixes the problem.

    @Sharable
    public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

        @Override
        public void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
            String message = byteBuf.toString(Charset.defaultCharset());
            System.out.println("Received Message : " + message);
        }

        @Override
        public void channelActive(ChannelHandlerContext channelHandlerContext){
            channelHandlerContext.writeAndFlush(Unpooled.copiedBuffer("Netty Rocks!", CharsetUtil.UTF_8));
        }

    }
user51
  • 8,843
  • 21
  • 79
  • 158
  • Thanks for the answer but this not what I was looking for , I need to execute multiple message on the base of response I get. something similar to this https://stackoverflow.com/a/35318079/1450401 – edwin Dec 21 '18 at 08:43