Netty的TCP粘包、拆包问题之FixedLengthFrameDecoder

上一篇说到Netty在处理TCP粘包拆包问题的三种解决方案。 消息定长、分隔符和自定义协议(消息头和消息体),也给分隔符一个例子了,现在下面我们就弄一个消息定长的例子和说一下需要注意的地方。
详细代码就不放了,代码和上个例子的是一样的。
1.1、首先用到定长解码器服务端是在childHandler方法的初始化通道方法里面
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//设置定长字符串接收(5个长度)
sc.pipeline().addLast(new FixedLengthFrameDecoder(5));
//设置字符串形式的编码
sc.pipeline().addLast(new StringEncoder());
//设置字符串形式的解码,以后在Handler那里获取的msg就是String类型的了。
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler()); //配置具体数据接收方法的处理器
}
});

1.2、然后修改ServeHandler的channelRead方法。
因为定长是五个长度嘛,那我们先试一下只发长度为3的看看,定长解码器会怎么处理。
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//因为配置了字符串形式的解码,所以msg会是String类型
String data = (String)msg;
System.out.println("Server接收到的数据:"+data);
//服务器给客户端返回数据
String str = "fff";
ctx.writeAndFlush(str);
}

1.3、客户端的初始化通道的方法也是要改为定长解码器。
//绑定事件处理器
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//设置定长字符串接收
sc.pipeline().addLast(new FixedLengthFrameDecoder(5));
//设置字符串形式的编码
sc.pipeline().addLast(new StringEncoder());
//设置字符串解码
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ClientHandler());
}
});
1.4、ClientHandler就不用改了,只是将服务端发送的数据直接打印出来而已。我们需要改的是客户端发送数据的代码。
定长是5,那么我们测试发长度为15的,看服务器的定长解码器是怎么处理的
cf.channel().writeAndFlush("aaaaabbbbbccccc"); //15个长度

1.5、执行结果:
服务端的:
Server接收到的数据:aaaaa
Server接收到的数据:bbbbb
Server接收到的数据:ccccc
小结:可以看到,客户端就算是发的是15个长度的数据,但是服务端还是每次只接收5个,将15个长度的分为三次接收。但是需要注意,就算分为三次接收,也只是一次通信。所以服务端只会返回一次数据。
客户端:
Client接收到的数据:fffff
小结:虽然服务端只是发了三个长度的数据,但是客户端接收到的还是5个长度的数据,定长解码器帮它补全了。但是有一个猜测,这里因为全部是字符f,所以补全也是补f,那如果是abc呢。下面做个测试。

2.1、服务端返回的数据改为abc:
String str = "abc";
ctx.writeAndFlush(str);

2.2、执行结果:
服务端:不变
Server接收到的数据:aaaaa
Server接收到的数据:bbbbb
Server接收到的数据:ccccc
客户端:重点观察
Client接收到的数据:abcab
小结:观察可得,补全的话,是从头拿然后补全,例如数据为三个长度,但是定长为五个长度,那么会从头拿数据的两个长度,然后到数据后面补全。例如 abc补全后abcab,edf补全后edfed。


总结:netty通信使用定长解码器的话,如果超长了会按定了的长度截取,如果不足的话,先取数据的前n位数据(n=定了的长度-数据长度),然后补在数据后面达到定了的长度

猜你喜欢

转载自blog.csdn.net/howinfun/article/details/81059952