我是靠谱客的博主 机智睫毛,最近开发中收集的这篇文章主要介绍解决Netty消息超长导致拆成多条消息(拆包)解决Netty消息超长导致拆成多条消息(拆包),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
解决Netty消息超长导致拆成多条消息(拆包)
遇到问题的场景
问题的起源是因为帮朋友用socket做一个消息中转,然后就发现了他每次发送的消息都特别长导致channelread会读到多次,最开始图了省事手动去处理的拆包(这种比较恶心,要协定好消息的前缀和后缀才能去灵活的拼接消息,代码写起来也比较恶心,但是好在可以实现),然后研究了一下正常的解决方案,自定义协议
解决问题
首先双方需要协商一下协议所需要包含的内容,比如
- 头部信息,可以包含一些特殊信息可以被解析出来并特殊处理
- 消息长度,设定固定的长度
- 消息体内容
- 等等其他需要包含的信息
开始定义一个可以解决我如上所述问题的协议,然后定义一个对象包含如下信息
private int head = 824; //这里自定义
private int contentLength; //content的长度
private byte[] content; //消息的具体内容
自定义解码器(客户端是普通socket不是netty所以只自定义了解码)
public class YuDecode extends ByteToMessageDecoder {
private final int LENGTH = 4 + 4 ;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
//head 4字节
//length 4字节
if(in.readableBytes() >= LENGTH){
//符合协议
if(in.readableBytes() > 16392){
System.out.println("超过协议定义大小" + in.readableBytes());
//限制数据大小
in.skipBytes(in.readableBytes());
}
int begin;
while(true){
//开始的位置
begin = in.readerIndex();
//标记
in.markReaderIndex();
if(in.readInt() == 824){
//每次读4个字节 读到了包头 符合要求
System.out.println("读到了包头");
break;
}
//没读到包头重置读取位置
in.resetReaderIndex();
//略过一个字节重新读
in.readByte();
if(in.readableBytes() < LENGTH){
System.out.println("没有读到包头");
return;
}
}
//消息长度
int contentLength = in.readInt();
if(in.readableBytes() < contentLength){
System.out.println("消息的内容长度没有达到预期设定的长度,还原指针重新读");
//消息的内容长度没有达到预期设定的长度,还原指针重新读
in.readerIndex(begin);
return;
}
byte[] content = new byte[contentLength];
in.readBytes(content);
YuSocket protocol = new YuSocket();
protocol.setHead(824);
protocol.setContent(content);
protocol.setContentLength(contentLength);
System.out.println(contentLength);
out.add(protocol);
}
System.out.println("不符合协议内容");
}
}
配置初始化通道和nettyserver
NioEventLoopGroup workGroup = new NioEventLoopGroup();
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(workGroup,bossGroup);
serverBootstrap.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler("DEBUG"));
ch.pipeline().addLast(new YuEncode());
ch.pipeline().addLast(new YuDecode());
ch.pipeline().addLast(new ServerHandler());
}
});
try {
ChannelFuture sync = serverBootstrap.bind(8080).sync();
sync.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
测试的socket客户端发送的长度为16384字节,比较大了吧
Socket socket = new Socket("127.0.0.1",8080);
socket.setKeepAlive(true);
boolean connected = socket.isConnected();
OutputStream outputStream = socket.getOutputStream();
String ss="太长了...";
YuSocket yuSocket = new YuSocket();
yuSocket.setHead(824);
yuSocket.setContentLength(ss.length());
yuSocket.setContent(ss.getBytes());
byte[] bytes = toByteArray(yuSocket);
System.out.println(bytes.length);
outputStream.write(bytes);
outputStream.flush();
这样完整的一条信息就读出来了,不用分批次接受手动组装了.
不想手撸一遍的看这里:Click me to github
最后
以上就是机智睫毛为你收集整理的解决Netty消息超长导致拆成多条消息(拆包)解决Netty消息超长导致拆成多条消息(拆包)的全部内容,希望文章能够帮你解决解决Netty消息超长导致拆成多条消息(拆包)解决Netty消息超长导致拆成多条消息(拆包)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复