2017-08-21 48 views
0

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

服务器:

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

}

回答

1

你的测试程序假设连接获取写入数据后关闭,而其假设字符串不发送多字节字符的情况下支离破碎。

如果等到套接字关闭是故意的,你需要改变你的write声明如下:

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

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

柜面服务器需要收到一条消息,你应该在你的管道的起点,后面跟着一个可选new StringDecoder()添加new LineBasedFrameDecoder()让网状自动打开ByteBuf s转换的字符串,你不必这样做了。 Netty也可以使用StringEncoder来反向执行此操作,因此您只需编写一个字符串对象,而不是每次将其包装在ByteBuf中。

+0

我明白了。如果服务器关闭套接字,'read(buffer)!= -1'成立。但是,我不希望这样的协议是基于二进制的。请求和响应以二进制形式发送,固定头大小为17字节,可选体也是二进制形式。当我知道从头部读取的确切响应体大小时,是否需要分隔符?如果是,如何? –

0

看到最后一个问题。整个问题都与测试客户端有关。

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


第二个问题:
第二个问题是,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()); 
} 

}

相关问题