Java netty客户端无法向服务器发送消息,但telnet到服务器确定

时间:2017-12-06 13:35:19

标签: java sockets netty telnet

我正在学习Java Netty,通过socket 7000创建非常简单的客户端服务器。服务器正在运行,它将回显从客户端收到的消息。如果我使用telnet localhost 7000并向服务器发送消息并接收回显消息,它就可以工作。

但是,使用Java Netty客户端,它不起作用。服务器什么都没收到,客户端什因为我试图在控制台上添加一些写作。

以下是此示例的类:

客户端

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);
    }
}

服务器

    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();
    }
}

所以当我运行EchoServer,然后运行EchoClient时,EchoClient的输出是

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

EchoServer的输出是

Sending message: message from server.

2 个答案:

答案 0 :(得分:3)

在您的代码中,DelimiterBasedFrameDecoder处理程序在解码器/编码器之前到来。因此,如果传送的消息没有预期的分隔符(例如,在这种情况下为新行),则客户端/服务器将继续等待并认为该消息仍在传送。因此,有两种方法可以解决您的问题。

  1. 删除客户端和服务器中的new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter())
  2. 每次通过频道发送消息时,请添加新的行分隔符。否则,无法从另一端解码消息。请在下面找到示例代码
  3. EchoClientHandler类

    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类

      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());
        }
    }
    

    服务器输出

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

    客户端输出

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

答案 1 :(得分:0)

比较您的客户端和telnet之间的协议(使用LoggingHandler或Wireshark),如果这样做,您会注意到这两个协议之间存在一个主要区别。

不同之处在于,您在最后没有新换行符的情况下发送邮件,而telnet则会这样做。

通过在邮件末尾添加新换行符,或编写一个自动为您执行此操作的新处理程序,解决此问题非常简单。

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

您可以做的另一项改进是调用writeAndFlush而不是先写入,然后刷新,这也可以防止您在编码时被中断时错过对其他方法的调用。