简体   繁体   中英

Java netty client cannot send message to server, but telnet to sever ok

I'm just learning Java Netty to make very simple client-server via socket 7000. Server is running and it will echo the message received from client. It works if I use telnet localhost 7000 and send message to server and receive the echo message.

However, with a Java Netty client, it doesn't work. Server receives nothing, client sends nothing? as I tried to add some writing to console.

Here is the classes of this example:

Client

public final class EchoClient {

    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(
                                    new LoggingHandler(LogLevel.TRACE),
                                    new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()),
                                    new StringEncoder(),
                                    new StringDecoder(),
                                    new EchoClientHandler());
                        }
                    });

            // Start the connection attempt.
            bootstrap.connect("localhost", 7000).sync().channel().closeFuture().sync();
            System.out.println("Message sent successfully.");
        } finally {
            group.shutdownGracefully();
        }
    }
}

public class EchoClientHandler extends SimpleChannelInboundHandler<String> {


    /**
     * Constructor for the class
     *
     * @param message the message you want to transmit
     */
    public EchoClientHandler() {

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String message = "message from client.";
        System.out.println("Sending message: " + message);
        ctx.write(message);
        ctx.flush();
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("Error caught in the communication service: " + cause);
        ctx.close();
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("Received message: " + msg);
    }
}

Server

    public final class EchoServer {

    static final boolean SSL = System.getProperty("ssl") != null;
    static final int PORT = Integer.parseInt(System.getProperty("port", "7000"));

    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.TRACE))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(
                                    new LoggingHandler(LogLevel.TRACE),
                                    new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()),
                                    new StringEncoder(),
                                    new StringDecoder(),
                                    new EchoServerHandler());
                        }
                    });

            System.out.println("Server is listening on port 7000.");

            // Start the server.
            ChannelFuture channelFuture = serverBootstrap.bind("localhost", 7000).sync();

            // Wait until the server socket is closed.
            channelFuture.channel().closeFuture().sync();


        } finally {
            // Shut down all event loops to terminate all threads.
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}



public class EchoServerHandler extends SimpleChannelInboundHandler<String> {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String message = "message from server.";
        System.out.println("Sending message: " + message);
        ctx.write(message);
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        System.out.println("Error in receiving message.");
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
        System.out.println("Received message: " + message);
        ctx.write(message);
        ctx.flush();
        //ctx.close();
    }
}

So when I run EchoServer, then I run EchoClient, the output from EchoClient is

Sending message: message from client.
Message sent successfully.
Then application stopped.

And the output from EchoServer is

Sending message: message from server.

In your code, the DelimiterBasedFrameDecoder handler is coming before decoder/encoder. Hence, if the transferred message is without expected delimiter (eg new line in this case), both client/server will continue waiting and think that message is still transferring. Hence, there are two possible ways to fix your issue.

  1. Remove new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()) in both Client and Server
  2. Every time you send message over the channel, please add new line separator. Otherwise, the message can't be decoded from other end. Please find below the sample code

EchoClientHandler class

public class EchoClientHandler extends SimpleChannelInboundHandler<String> {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String message = "message from client.";
        System.out.println("Sending message: " + message);
        ctx.writeAndFlush(message + System.lineSeparator());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("Error caught in the communication service: " + cause);
        ctx.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("Received message: " + msg);
    }
}

EchoServerHandler class

  public class EchoServerHandler extends SimpleChannelInboundHandler<String> {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String message = "message from server.";
        System.out.println("Sending message: " + message);
        ctx.writeAndFlush(message + System.lineSeparator());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("Error in receiving message.");
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
        System.out.println("Received message: " + message);
        ctx.writeAndFlush(message + System.lineSeparator());
    }
}

Output from Server

Server is listening on port 7000.
Sending message: message from server.
Received message: message from client.

Output from Client

Sending message: message from client.
Received message: message from server.
Received message: message from client.

Compare your protocol between your client and telnet (using LoggingHandler or Wireshark), if you do this, you will notice that there is 1 major difference between those 2 protocols.

The difference is the fact that you send your messages without a new newline at the end, while telnet does.

Solving this is really easy by appending a new newline at the end of your message, or writing a new handler that does this automatically for you.

ctx.write(message + "\n");

One other improvement you could make is calling writeAndFlush instead of first write, and then flush, this also prevents you from missing the call to the other method when you get interrupted while coding.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM