我是使用Netty Framework的新手。我遇到问题,我用Netty编写ServerSocket。 服务器的目标是从硬件接收消息。硬件每次都发送一个字节。服务器和硬件都有一个协议 - 每条消息都以'#'开头,以' *'结束。
@Sharable
class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
BytBuf in = (ByteBuf) msg;
CharBuffer charBuffer = CharBuffer.allocate(100);
String recedata ;
byte tmp;
try {
while (in.isReadable()) {
tmp = in.readByte();
if (tmp != 42) {
charBuffer.append((char) tmp);
// System.out.println(String.valueOf(charBuffer.array()));
} else { //means receive a byte '*'
charBuffer.append('*');
count = 0;
recData = String.valueOf(charBuffer.array());
logger.debug("receive message is " + recData);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
然而,出现问题。当硬件首次发送#abcd
时,服务器将存储#abcd
然后硬件可能会发送efg*
。由于Netty是异步和事件驱动的,因此方法ChannelRead()
将从头到尾运行。因此将打印efg*
,而不是#abcdefg*
我想了很多。最后,我有一个想法。我使用类似AttribueKey
的{{1}}来绑定一个数组,以便将所有接收到的字节与通道一起存储。然后我从数组中得到ThreadLocal
。但阵列非常大。这不是一个好方法。
你有更好的方法来解决我的问题吗?谢谢你的帮助
答案 0 :(得分:1)
查看Netty用户指南 - 处理基于流的传输。消息可能会碎片化 - 因此在您的情况下,它可能会收到#ab;#abcd"然后是" efg *"。由于每次都要分配一个CharBuffer,原始的CharBuffer包含"#abcd"。在第二个方法调用中,CharBuffer包含" efg *"。
解决方案是使用ByteToMessageDecoder。 decode()将被重复调用(通过Netty框架),直到ByteBuf为空(即,您的解码代码将其清空)。所以你在decode()中可以做的就是继续返回,直到" in" ByteBuf包含* char。完成后,将ByteBuf的内容写入" out"列表从开头#到*。 *之后的任何剩余字节将在ByteBuf中保留,并且该过程将继续。