2015-12-02 35 views
0

我正在嘗試使用netty編寫一個簡單的客戶端服務器應用程序。 我跟着this教程,特別是時間服務器模型以及POJO模型。我的問題在於ByteToMessageDecoder:它運行的次數超過它的意義,這意味着當它讀取一個空的ByteBuf而不是停止時,它會再次讀取一段時間,並且由於某種原因,我無法理解,它會發現先前的消息,送!我確信客戶端只發送一次該消息!Netty ByteToMessageDecoder運行的次數多於

所以這個想法是:一個簡單的客戶端服務器模型,其中客戶端發送帶有「hello world」消息的「DataPacket」並且服務器用「ACK」響應「DataPacket」。我正在使用DataPacket類型,因爲將來我想要傳遞更多的東西,添加一個頭文件並構建一些更復雜的內容...但對於初學者,我需要看看我在這一個中做了什麼錯誤...

的錯誤: Error of my application

正如你可以看到服務器正常啓動,我的客戶(收發器)發送消息,編碼器激活,並從DataPacket其轉換爲ByteBuf,該消息被髮送和接收服務器,解碼器從服務器激活並將其從ByteBuf轉換爲DataPacket,然後服務器相應地處理它...它應該發送ACK並向後重複,但這是事情出錯了,我不明白爲什麼。

我已經讀到這裏一些帖子,並且已經嘗試了LengthFieldBasedFrameDecoder,它沒有工作,我也想看看什麼是錯的這一個,如果可能的,而不是用別的...

代碼:

編碼器和解碼器類:

package org.client_server; 

import java.util.List; 

import io.netty.buffer.ByteBuf; 
import io.netty.channel.ChannelHandlerContext; 
import io.netty.handler.codec.ByteToMessageDecoder; 
import io.netty.handler.codec.MessageToByteEncoder; 
import io.netty.util.CharsetUtil; 

public class EncoderDecoder { 

    public static class NettyEncoder extends MessageToByteEncoder<DataPacket> { 

     @Override 
     protected void encode(ChannelHandlerContext ctx, DataPacket msg, ByteBuf out) 
       throws Exception { 
      System.out.println("Encode: "+msg.getData()); 
      out.writeBytes(msg.convertData()); 
     }  
    } 

    public static class NettyDecoder extends ByteToMessageDecoder{ 

     @Override 
     protected void decode(ChannelHandlerContext ctx, ByteBuf in, 
       List<Object> out) throws Exception { 
      if((in.readableBytes() < 4)) { 
       return; 
      } 
      String msg = in.toString(CharsetUtil.UTF_8); 
      System.out.println("Decode:"+msg); 

      out.add(new DataPacket(msg)); 
     } 

    } 

} 

服務器處理器:

class DataAvroHandler extends ChannelInboundHandlerAdapter { 


     @Override 
     public void channelRead(ChannelHandlerContext ctx, Object msg) 
       throws Exception { 
      try { 
       DataPacket in = (DataPacket)msg; 
       System.out.println("[Server]: Message received..."+in.getData()); 
      }finally { 
       ReferenceCountUtil.release(msg); 
       //ctx.close(); 
      } 
     } 

     @Override 
     public void channelReadComplete(ChannelHandlerContext ctx) 
       throws Exception { 
      System.out.println("[Server]: Read Complete..."); 
      DataPacket pkt = new DataPacket("ACK!"); 
      //pkt.setData(Unpooled.copiedBuffer("ACK", CharsetUtil.UTF_8)); 
      ctx.writeAndFlush(pkt);   
     } 

     @Override 
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) 
       throws Exception { 
      serverLog.warning("[Server]: Error..." + cause.toString()); 
      ctx.close();    
     } 

客戶端處理程序:

class DataAvroHandlerCl extends ChannelInboundHandlerAdapter { 
    @Override 
    public void channelActive(ChannelHandlerContext ctx) throws Exception { 

     System.out.println("[Transceiver]: Channel Active!!!"); 
     DataPacket pkt = new DataPacket("Hello World!"); 
     ChannelFuture f = ctx.writeAndFlush(pkt); 
     //f.addListener(ChannelFutureListener.CLOSE); 
    } 

    @Override 
    public void channelRead(ChannelHandlerContext ctx, Object msg) { 
     try { 
      DataPacket in = (DataPacket)msg; 
      System.out.println("[Transceiver]: Message received..."+in.getData()); 
     }finally { 
      ReferenceCountUtil.release(msg); 
      //ctx.close(); 
     } 
    } 

    @Override 
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 
     transLog.warning("[Transceiver] : Error..." + cause.getMessage()); 
     ctx.close(); 
    } 

} 

服務器和客戶端的管道:

ch.pipeline().addLast("Decoder", new EncoderDecoder.NettyDecoder()); 
ch.pipeline().addLast("Encoder", new EncoderDecoder.NettyEncoder()); 
ch.pipeline().addLast("DataAvroHandler", new DataAvroHandler()); 

回答

2

您的問題,從使用ByteBuf intoString()方法在NettyDecoder出現。

從Javadoc中(http://netty.io/4.0/api/io/netty/buffer/ByteBuf.html#toString%28java.nio.charset.Charset%29)報價:

此方法不會修改此緩衝器的readerIndex或writerIndex。

現在,ByteToMessageDecoder不知道你實際解碼了多少字節!它看起來像你解碼0字節,因爲緩衝區的readerIndex沒有被修改,因此你也可以在你的控制檯中得到錯誤信息。

您必須手動修改readerIndex:

String msg = in.toString(CharsetUtil.UTF_8); 
in.readerIndex(in.readerIndex() + in.readableBytes()); 
System.out.println("Decode:"+msg); 
+0

謝謝!它完美的工作!對於記錄,因爲toString()應該避免什麼是一個很好的方法來轉換字符串? – Saraki

+2

你可以使用netty自己的StringDecoder(http://netty.io/4.0/api/io/netty/handler/codec/string/StringDecoder.html)。但看着實現,我發現它使用了'toString()'本身,所以在這裏看起來這很合適!通常'toString()'方法用於文本輸出,而不是真正的高性能,我推廣得太早 - 我道歉。 – DevCybran