【问题标题】:Simple Netty Server not sending response简单的 Netty 服务器不发送响应
【发布时间】:2017-08-21 06:50:49
【问题描述】:

我正在编写在 TCP 上运行的自定义协议搜索服务。使用 EmbeddedChannel 进行测试时一切正常。为了进一步测试,我编写了一个服务器并添加了处理程序。通过来自普通 java Socket 客户端的请求,服务器接收数据、处理并发送回响应。但是,响应没有到达客户端套接字。我想可能是我搞砸了大通道管道。所以我将实现减少到一个入站处理程序。还是不行。有人可以在这里帮忙吗?

服务器:

public void start() throws Exception{
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();

    try {
        final KaiExceptionHandler kaiExceptionHandler = new KaiExceptionHandler();
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new SimpleHandler());
                    }
                });
        ChannelFuture future = b.bind(new InetSocketAddress("localhost", 9400)).sync();
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if(channelFuture.isSuccess()) {
                    LOGGER.info("Kai Server is bounded to '{}'", "localhost:9400");
                }else {
                    LOGGER.error("Failed to bound Kai to 'localhost:9400'", channelFuture.cause());
                }
            }
        });
        future.channel().closeFuture().sync();
    }finally {
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

简单处理程序:

public class SimpleHandler extends ChannelInboundHandlerAdapter {

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    Charset charset = Charset.defaultCharset();
    ctx.write(Unpooled.copiedBuffer("Client is not seeing this", charset));
    ctx.flush();
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    ctx.flush();
} }

测试客户端。一个不整洁的实现。不过,只是为了测试。

public class TestClient {


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

    Socket socket = new Socket("localhost", 9400);
    InputStream is = socket.getInputStream();
    StringBuilder sb = new StringBuilder();
    byte[] buffer = new byte[64];
    int r = 0;
    socket.setSoTimeout(10000);
    System.out.println("Reading...");
    while ((r = is.read(buffer)) != -1) {
        sb.append(new String(buffer).trim());
    }
    System.out.println("String: " + sb.toString());
}

}

【问题讨论】:

    标签: netty


    【解决方案1】:

    您的测试程序假设在写入数据后连接关闭,并且它假设的字符串在发送多字节字符的情况下没有碎片。

    如果等待套接字关闭是有意的,您需要将write 语句更改为以下内容:

    ctx.write(Unpooled.copiedBuffer("Client is not seeing this", charset))
        .addListener(ChannelFutureListener.CLOSE);
    

    然而,这种通信方式效率低下,因为每次你想对服务器说些什么时,你都需要重新打开另一个套接字连接。最好的方法是使协议基于行或由长度字段分隔,然后使用BufferedReader 在客户端中逐行读取响应,在服务器端,您应该在每个末尾添加一个换行符消息。

    如果服务器需要接收消息,你应该在管道的开头添加一个new LineBasedFrameDecoder(),然后是一个可选的new StringDecoder(),让netty自动将ByteBufs变成字符串,你不需要不得不这样做了。 Netty 也可以使用StringEncoder 反向执行此操作,因此您只需编写一个字符串对象,而不是每次都将其包装在ByteBuf 中。

    【讨论】:

    • 我明白了。如果服务器关闭套接字,'read(buffer) != -1' 成立。但是,我不想要那个..协议是基于二进制的。请求和响应以二进制形式发送,具有 17 字节的固定标头大小和一个可选的正文,该正文也是二进制形式。当我知道要从标头读取的确切响应正文大小时,是否需要分隔符?如果是,怎么做?
    【解决方案2】:

    看到最后一个问题。整个问题出在测试客户端上。

    第一个问题:
    第一个是 Ferrybig 指出的,其中 read(buffer) != -1 期望套接字关闭(感谢那个人)。

    第二个问题:
    第二个是,ChannelInboundHandlerAdapter#channelRead(ChannelHandlerContext ctx, Object msg) 永远不会被调用,因为套接字不发送任何内容,因此没有什么可读取的。编辑我的客户以发送一些东西使其工作。

    新客户:

    public class TestClient {
    
    
    public static void main(String[] args) throws Exception {
    
        Socket socket = new Socket("localhost", 9400);
        socket.setSoTimeout(10000);
        OutputStream raw = socket.getOutputStream();
        // Will be the request bytes
        raw.write(1);
        raw.flush();
    
        InputStream is = socket.getInputStream();
        StringBuilder response = new StringBuilder();
        // actual expected size will be here
        final int expectedResponse = 128; 
        byte[] buffer = new byte[expectedResponse];
        int bytesRead = is.read(buffer);
        if (bytesRead != -1) {
            response.append(new String(buffer).trim()).append("\n");
        }
        System.out.println("String: " + response.toString());
    }
    

    }

    【讨论】:

      猜你喜欢
      • 2019-03-10
      • 2015-05-03
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多