2017-08-21 53 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()); 
} 

}

相關問題