2013-03-22 62 views
0

我正在使用Netty,并且似乎不会调用ChannelPipeline中的FrameDecoder,除非/直到收到回车。例如,我有我写尝试检测,当一个完整的JSON字符串已经收到了以下解码器:Netty FrameDecoder在ChannelPipeline中没有回车没有被调用?

public class JsonDecoder extends FrameDecoder { 
    @Override 
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) { 
     char inChar = 0; 
     ChannelBuffer origBuffer = buf.copy(); 
     StringBuilder json = new StringBuilder(); 
     int ctr = 0; 
     while(buf.readable()) { 
      inChar = (char) buf.readByte(); 
      json.append(inChar); 
      if (inChar == '{') { 
       ctr++; 
      } else if (inChar == '}') { 
       ctr--; 
      } 
     } 
     if (json.length() > 0 && ctr == 0) { 
      return origBuffer; 
     } 
     buf.resetReaderIndex(); 
     return null; 
    } 
} 

(请原谅有点草率代码 - 这是使用的Netty和我第一次尝试的学习体验一下。)

我看到发生什么事是,这当我使用telnet,贴在一些有效的JSON然后按回车键连接到服务器上测试它工作正常。但是,如果我在JSON字符串中的最后一次关闭'}'之后没有按回车,解码器将不会被更新的缓冲区调用。

是否有配置通道管道的工作方式不同的方式?我已经为此搜索并查看了Netty文档。我觉得我错过了一些基本的东西,我只是没有找到正确的地方或寻找正确的东西。谢谢你的帮助。

+0

此外,我应该提到,这只是通过TCP套接字连接传递的原始JSON - 不涉及HTTP协议。 – 2013-03-22 16:59:42

回答

1

是您的Telnet客户端恢复到模式的“老逐行”,从而只完成线发送到服务器(telnet man page)?尝试编写一个简单的Java客户端来发送消息。

+0

在这种情况下无关紧要。 FrameDecoder基类不会“中继”消息,直到它看到整个帧(即读新行) – 2013-03-23 13:07:27

+0

我不遵循。 FrameDecoder不知道帧是如何分隔的。在这个例子中,JsonDecoder确定在读取框架时通过返回非null值,这通过匹配开启和关闭大括号来确定。 ReplayingDecoder有助于此,但不是必需条件。我关于telnet'逐行'模式的观点是,这会导致客户端缓冲数据,直到输入被按下。这似乎与它在客户端断开刷新客户端缓冲区的情况下工作的事实相符。 – johnstlr 2013-03-25 08:51:34

+0

糟糕,你是对的。我错误地认为使用了DelimiterBasedFrameDecoder。抱歉。 – 2013-03-25 21:59:10

1

我想读一个JSON流更类似于读取HTTP流,因为你将不得不继续跟踪打开和关闭括号(和支架为好,应该JSON字符串是一个数组)。如果您查看HTTP解码器的源代码,您会发现它使用的是ReplayingDecoder。使用重放解码器不是必需的,但是如果整个消息被分割到多个缓冲区中,它会有很大的帮助。

FrameDecoders是指用于读取由特殊字符“框架”的消息(解码器由此得名)或具有长度字段前缀。

我也强烈建议使用DecoderEmbedder辅助类,这样就可以单元测试你的JSON解码器没有做实际的I/O。

+0

谢谢!我会尝试ReplayingDecoder - 我很乐观,这将根据您的答案解决问题并更多地阅读文档。一旦我有机会尝试它,请接受你的答案。 – 2013-03-23 17:56:10

+0

扩展ReplayingDecoder后我注意到的是解码仅在客户端断开连接时才被调用。客户端实际上会与服务器保持连接,并且在正常情况下不会断开连接,所以我需要在正在进行的基础上调用decode()。有没有办法用ReplayingDecoder做到这一点?或者我应该像IdleThreadHandler一样使用ReplayingDecoder来以某种方式触发缓冲区被读取,如果在相当短的时间内没有活动? – 2013-03-24 12:58:01

+0

只要接收缓冲区中有数据就调用decode()。其他事情正在发生;也许客户端缓冲数据;很难说没有更多的细节。 – 2013-03-24 16:26:59