您的位置:首页 > 文旅 > 美景 > Netty笔记08-粘包与半包(下)

Netty笔记08-粘包与半包(下)

2024/10/5 22:25:31 来源:https://blog.csdn.net/weixin_46425661/article/details/142260025  浏览:    关键词:Netty笔记08-粘包与半包(下)

文章目录

  • 解决方案
    • 方法1,短链接
    • 方法2,固定长度
    • 方法3,固定分隔符
    • 方法4,预设长度


解决方案

  1. 短链接,发一个包建立一次连接,这样连接建立到连接断开之间就是消息的边界,缺点效率太低
  2. 每一条消息采用固定长度,缺点浪费空间
  3. 每一条消息采用分隔符,例如 \n,缺点需要转义
  4. 每一条消息分为 head 和 body,head 中包含 body 的长度

方法1,短链接

以解决粘包为例
服务器端

/***  1.短链接解决粘包与半包*  半包用这种办法还是不好解决,因为当接收方的缓冲区大小有限时,还是会出现*/
public class HelloWorldServer {static final Logger log = LoggerFactory.getLogger(HelloWorldServer.class);void start() {NioEventLoopGroup boss = new NioEventLoopGroup(1);NioEventLoopGroup worker = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.channel(NioServerSocketChannel.class);// 调整系统的接受缓冲区(滑动窗口)
//            serverBootstrap.option(ChannelOption.SO_RCVBUF,10);// 调整netty的接受缓冲区(ByteBuf)//让缓冲区小于客户端发送的数据,从而出现半包问题serverBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator(16,16,16));serverBootstrap.group(boss, worker);serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));}});ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();log.debug("{} bound...", channelFuture.channel());channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("server error", e);} finally {boss.shutdownGracefully();worker.shutdownGracefully();log.debug("stoped");}}public static void main(String[] args) {new HelloWorldServer().start();}
}

客户端

public class HelloWorldClient {static final Logger log = LoggerFactory.getLogger(HelloWorldClient.class);public static void main(String[] args) {// 分 10 次发送for (int i = 0; i < 10; i++) {send();}}private static void send() {NioEventLoopGroup worker = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.channel(NioSocketChannel.class);bootstrap.group(worker);bootstrap.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {log.debug("conneted...");ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("sending...");ByteBuf buffer = ctx.alloc().buffer();
//                            buffer.writeBytes(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});buffer.writeBytes(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,16,17});ctx.writeAndFlush(buffer);// 发完即关ctx.close();}});}});ChannelFuture channelFuture = bootstrap.connect("localhost", 8080).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("client error", e);} finally {//关闭NioEventLoopGroup线程worker.shutdownGracefully();}}
}

半包问题用短连接办法还是无法解决,因为接收方的缓冲区大小是有限的

//让缓冲区小于客户端发送的数据,从而出现半包问题
serverBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator(16,16,16));

服务器输出

Connected to the target VM, address: '127.0.0.1:5260', transport: 'socket'
23:10:34 [DEBUG] [main] c.i.n.n.HelloWorldServer - [id: 0xcb563f8f, L:/0:0:0:0:0:0:0:0:8080] bound...
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 - R:/127.0.0.1:5421] REGISTERED
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 - R:/127.0.0.1:5421] ACTIVE
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 - R:/127.0.0.1:5421] READ: 16B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
+--------+-------------------------------------------------+----------------+
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 - R:/127.0.0.1:5421] READ COMPLETE
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 - R:/127.0.0.1:5421] READ: 2B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 10 11                                           |..              |
+--------+-------------------------------------------------+----------------+
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 - R:/127.0.0.1:5421] READ COMPLETE
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 - R:/127.0.0.1:5421] READ COMPLETE
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 ! R:/127.0.0.1:5421] INACTIVE
23:10:49 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0xae87ef78, L:/127.0.0.1:8080 ! R:/127.0.0.1:5421] UNREGISTERED
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 - R:/127.0.0.1:5487] REGISTERED
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 - R:/127.0.0.1:5487] ACTIVE
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 - R:/127.0.0.1:5487] READ: 16B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
+--------+-------------------------------------------------+----------------+
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 - R:/127.0.0.1:5487] READ COMPLETE
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 - R:/127.0.0.1:5487] READ: 2B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 10 11                                           |..              |
+--------+-------------------------------------------------+----------------+
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 - R:/127.0.0.1:5487] READ COMPLETE
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 - R:/127.0.0.1:5487] READ COMPLETE
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 ! R:/127.0.0.1:5487] INACTIVE
23:10:49 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0xff5ce013, L:/127.0.0.1:8080 ! R:/127.0.0.1:5487] UNREGISTERED

方法2,固定长度

让所有数据包长度固定(假设长度为 8 字节),服务器端加入

@Slf4j
public class Server2 {void start() {NioEventLoopGroup boss = new NioEventLoopGroup();NioEventLoopGroup worker = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.channel(NioServerSocketChannel.class);// 调整系统的接收缓冲区(滑动窗口)
//            serverBootstrap.option(ChannelOption.SO_RCVBUF, 10);// 调整 netty 的接收缓冲区(byteBuf)serverBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(16, 16, 16));serverBootstrap.group(boss, worker);serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {//先定长在打印日志ch.pipeline().addLast(new FixedLengthFrameDecoder(10));ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));}});ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("server error", e);} finally {boss.shutdownGracefully();worker.shutdownGracefully();}}public static void main(String[] args) {new Server2().start();}
}

客户端

public class Client2 {static final Logger log = LoggerFactory.getLogger(Client1.class);public static void main(String[] args) {send();System.out.println("finish");}public static byte[] fill10Bytes(char c, int len) {byte[] bytes = new byte[10];Arrays.fill(bytes, (byte) '_');for (int i = 0; i < len; i++) {bytes[i] = (byte) c;}System.out.println(new String(bytes));return bytes;}private static void send() {NioEventLoopGroup worker = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.channel(NioSocketChannel.class);bootstrap.group(worker);bootstrap.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {// 会在连接 channel 建立成功后,会触发 active 事件@Overridepublic void channelActive(ChannelHandlerContext ctx) {ByteBuf buf = ctx.alloc().buffer();char c = '0';Random r = new Random();for (int i = 0; i < 10; i++) {//返回10字节的数据byte[] bytes = fill10Bytes(c, r.nextInt(10) + 1);c++;buf.writeBytes(bytes);}ctx.writeAndFlush(buf);}});}});ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("client error", e);} finally {worker.shutdownGracefully();}}
}

服务器输出

23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] REGISTERED
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] ACTIVE
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 30 30 5f 5f 5f 5f 5f 5f 5f 5f                   |00________      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ COMPLETE
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 31 31 31 5f 5f 5f 5f 5f 5f 5f                   |111_______      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 32 32 32 5f 5f 5f 5f 5f 5f 5f                   |222_______      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ COMPLETE
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 33 33 33 33 33 5f 5f 5f 5f 5f                   |33333_____      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ COMPLETE
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 34 34 34 34 34 34 34 34 34 5f                   |444444444_      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 35 35 35 35 35 35 35 35 35 35                   |5555555555      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ COMPLETE
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 36 36 36 36 36 5f 5f 5f 5f 5f                   |66666_____      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 37 37 37 37 5f 5f 5f 5f 5f 5f                   |7777______      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ COMPLETE
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 38 38 38 38 38 38 38 38 5f 5f                   |88888888__      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ COMPLETE
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ: 10B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 39 39 39 39 39 5f 5f 5f 5f 5f                   |99999_____      |
+--------+-------------------------------------------------+----------------+
23:06:19 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x6db3f05c, L:/127.0.0.1:8080 - R:/127.0.0.1:4958] READ COMPLETE

方法3,固定分隔符

服务端加入,默认以 \n 或 \r\n 作为分隔符,如果超出指定长度仍未出现分隔符,则抛出异常

@Slf4j
public class Server3 {void start() {NioEventLoopGroup boss = new NioEventLoopGroup();NioEventLoopGroup worker = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.channel(NioServerSocketChannel.class);// 调整系统的接收缓冲区(滑动窗口)
//            serverBootstrap.option(ChannelOption.SO_RCVBUF, 10);// 调整 netty 的接收缓冲区(byteBuf)serverBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(16, 16, 16));serverBootstrap.group(boss, worker);serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {//\n和\r\n分隔符ch.pipeline().addLast(new LineBasedFrameDecoder(1024));//自定义分割符//DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter)
//                    ch.pipeline().addLast(new DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter));ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));}});ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("server error", e);} finally {boss.shutdownGracefully();worker.shutdownGracefully();}}public static void main(String[] args) {new Server3().start();}
}

客户端在每条消息之后,加入 \n 分隔符

public class Client3 {static final Logger log = LoggerFactory.getLogger(Client1.class);public static void main(String[] args) {send();System.out.println("finish");}public static StringBuilder makeString(char c, int len) {StringBuilder sb = new StringBuilder(len + 2);for (int i = 0; i < len; i++) {sb.append(c);}sb.append("\n");return sb;}private static void send() {NioEventLoopGroup worker = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.channel(NioSocketChannel.class);bootstrap.group(worker);bootstrap.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {// 会在连接 channel 建立成功后,会触发 active 事件@Overridepublic void channelActive(ChannelHandlerContext ctx) {ByteBuf buf = ctx.alloc().buffer();char c = '0';Random r = new Random();for (int i = 0; i < 10; i++) {//随时生成1-257长度的字节,并以"\n"结尾StringBuilder sb = makeString(c, r.nextInt(256) + 1);c++;buf.writeBytes(sb.toString().getBytes());}ctx.writeAndFlush(buf);}});}});ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("client error", e);} finally {worker.shutdownGracefully();}}
}

服务器输出

23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] REGISTERED
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] ACTIVE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ: 123B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
|00000010| 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
|00000020| 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
|00000030| 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
|00000040| 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
|00000050| 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
|00000060| 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
|00000070| 30 30 30 30 30 30 30 30 30 30 30                |00000000000     |
+--------+-------------------------------------------------+----------------+
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ COMPLETE
23:20:27 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x01478018, L:/127.0.0.1:8080 - R:/127.0.0.1:6891] READ: 46B+-------------------------------------------------+|  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
|00000010| 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
|00000020| 31 31 31 31 31 31 31 31 31 31 31 31 31 31       |11111111111111  |
+--------+-------------------------------------------------+----------------+

方法4,预设长度

在发送消息前,先约定用定长字节表示接下来数据的长度

public LengthFieldBasedFrameDecoder(// 真实的最大长度,超过该长度还没有发现分割标准则为失败int maxFrameLength,// 长度字段偏移量// 开始读取时的位置(从哪开始读)int lengthFieldOffset, // 长度字段长度(让服务器知道一条完整的消息的长度)// 负责记录消息所发送消息的长度(不是记录整个消息的长度)int lengthFieldLength,// 长度字段为基准,还有几个字节是内容// 读完长度字段后,跳过几个字节int lengthAdjustment, // 从头剥离几个字节// 从头开始放弃几个字节int initialBytesToStrip)

测试代码

public class TestLengthFieldDecoder {public static void main(String[] args) {EmbeddedChannel channel = new EmbeddedChannel(
//                new LengthFieldBasedFrameDecoder(
//                        1024, 0, 4, 0,0),
//                new LengthFieldBasedFrameDecoder(
//                        1024, 0, 4, 0,4),//设置消息最大为1024,长度从0开始,长度存储占有了4个字节,跳过1个字节,将前五个字节去掉(跳过长度存储的位置和额外加的字节位置)new LengthFieldBasedFrameDecoder(1024, 0, 4, 1,5),new LoggingHandler(LogLevel.DEBUG));//  4 个字节的内容长度, 实际内容ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();send(buffer, "Hello, world");send(buffer, "Hi!");//写入channel,模拟客户端发送channel.writeInbound(buffer);}private static void send(ByteBuf buffer, String content) {byte[] bytes = content.getBytes(); // 实际内容int length = bytes.length; // 实际内容长度buffer.writeInt(length);//writeInt为4个字节,并且为大端表示法buffer.writeByte(1);//注意可能出现TooLongFrameException: Adjusted frame length exceeds 1024: 1677721604 - discarded//因为writeInt()中设置了长度,但是这里又多了一个字节,就会导致读消息体时漏掉一个字节,// 消息体剩下的那个字节会被当成存储的的消息长度,因此报错。buffer.writeBytes(bytes);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com