TCP粘包拆包及NETTY解决方案

2023-11-06 02:40

本文主要是介绍TCP粘包拆包及NETTY解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第一个netty应用

pom

<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.16.Final</version>
</dependency>

EchoServer

package com.aegis.netty.demo1;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class EchoServer {public static void main(String[] args) throws Exception{//创建boss和worker线程(1)EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();//服务端是ServerBootstrapServerBootstrap b = new ServerBootstrap();//初始化boss和work线程化两个线程(3)b.group(bossGroup, workerGroup)//声明NioServerSocketChannel(4).channel(NioServerSocketChannel.class)//初始化客户端Handler(5).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) {ch.pipeline().addLast(new EchoServerHandler());}});//绑定端口(6)ChannelFuture f = b.bind(8888).sync();f.channel().closeFuture().sync();}
}

EchoServerHandler

package com.aegis.netty.demo1;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;public class EchoServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf in = (ByteBuf) msg;System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));}
}

EchoClient

package com.aegis.netty.demo1;import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;public class EchoClient {public static void main(String[] args) throws Exception{EventLoopGroup group = new NioEventLoopGroup();//客户端是BootstrapBootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress("localhost", 8888)).handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch)throws Exception {ch.pipeline().addLast(new EchoClientHandler());}});ChannelFuture future = b.connect().sync();Channel channel = future.channel();channel.writeAndFlush(Unpooled.copiedBuffer(("客户端第1条消息" + channel.remoteAddress()).getBytes()));channel.writeAndFlush(Unpooled.copiedBuffer("客户端第2条消息".getBytes()));channel.writeAndFlush(Unpooled.copiedBuffer("客户端第3条消息".getBytes()));channel.closeFuture().sync();    }
}

EchoClientHandler

package com.aegis.netty.demo1;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;public class EchoClientHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {//System.out.println("客户端收到消息:[" + msg + "]");ByteBuf in = (ByteBuf) msg;System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));}
}

tcp拆包粘包

现象

上述代码客户端连上服务端后,发了三条消息分别是:客户端第1条localhost/127.0.0.1:8888 、客户端第2条消息、客户端第3条消息.服务端的逻辑是每次收到一条消息就打印出来,并给服务端回复三条消息我是服务端、我是服务端、我是服务端。所以服务端会收到3条消息,并给客户端返回9条消息,客户端能收到9条消息。但是由于TCP 粘包拆包原因,结果往往出乎意料

  1. 服务端收到3条消息,客户端收到6条消息

  1. 服务端收到3条消息,客户端收到一条消息

3、客户端服务端都收到一条消息

。。。。。各种可能

原因

抓包

wireshark

【最详细】Wireshark使用教程_未名编程的博客-CSDN博客_wireshark使用教程入门

代码中的消息改成了英文,方便展示,下面是抓到的包

0000 02 00 00 00 45 00 00 51 22 06 40 00 80 06 00 00 ....E..Q".@.....

0010 7f 00 00 01 7f 00 00 01 d0 06 22 b8 6b d7 1e ab ..........".k...

0020 bb 04 71 8f 50 18 08 05 95 64 00 00 63 6c 69 65 ..q.P....d..clie

0030 6e 74 20 31 20 6d 65 73 73 61 67 65 6c 6f 63 61 nt 1 messageloca

0040 6c 68 6f 73 74 2f 31 32 37 2e 30 2e 30 2e 31 3a lhost/127.0.0.1:

0050 38 38 38 38 24 8888$

0000 02 00 00 00 45 00 00 39 22 14 40 00 80 06 00 00 ....E..9".@.....

0010 7f 00 00 01 7f 00 00 01 d0 06 22 b8 6b d7 1e d4 ..........".k...

0020 bb 04 71 8f 50 18 08 05 1f 96 00 00 63 6c 69 65 ..q.P.......clie

0030 6e 74 20 32 20 6d 65 73 73 61 67 65 24 nt 2 message$

0000 02 00 00 00 45 00 00 39 22 18 40 00 80 06 00 00 ....E..9".@.....

0010 7f 00 00 01 7f 00 00 01 d0 06 22 b8 6b d7 1e e5 ..........".k...

0020 bb 04 71 8f 50 18 08 05 1f 84 00 00 63 6c 69 65 ..q.P.......clie

0030 6e 74 20 33 20 6d 65 73 73 61 67 65 24 nt 3 message$

下面是服务端收到的包,也就是channelRead中ByteBuf 16进制打印结果

 

63 6c 69 65 6e 74 20 31 20 6d 65 73 73 61 67 65 6c 6f 63 61 6c 68 6f 73 74 2f 31 32 37 2e 30 2e 30 2e 31 3a 38 38 38 38 24 63 6c 69 65 6e 74 20 32 20 6d 65 73 73 61 67 65 24 63 6c 69 65 6e 74 20 33 20 6d 65 73 73 61 67 65 24

netty解决tcp 粘包拆包方案

  1. 定长FixedLengthFrameDecoder

  2. 特殊字符切割DelimiterBasedFrameDecoder

下面以$符号作为切割符,分别在客户端和服务端添加DelimiterBasedFrameDecoder。发送的消息末尾加上$

ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
channel.writeAndFlush(Unpooled.copiedBuffer("客户端第2条消息$".getBytes()));

结果如下:服务端收到3条消息,客户端收到9条消息

        3.自定义协议实现文件的上传下载(后面介绍)

这篇关于TCP粘包拆包及NETTY解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/354008

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

在MySQL执行UPDATE语句时遇到的错误1175的解决方案

《在MySQL执行UPDATE语句时遇到的错误1175的解决方案》MySQL安全更新模式(SafeUpdateMode)限制了UPDATE和DELETE操作,要求使用WHERE子句时必须基于主键或索引... mysql 中遇到的 Error Code: 1175 是由于启用了 安全更新模式(Safe Upd

Python安装时常见报错以及解决方案

《Python安装时常见报错以及解决方案》:本文主要介绍在安装Python、配置环境变量、使用pip以及运行Python脚本时常见的错误及其解决方案,文中介绍的非常详细,需要的朋友可以参考下... 目录一、安装 python 时常见报错及解决方案(一)安装包下载失败(二)权限不足二、配置环境变量时常见报错及

Java下载文件中文文件名乱码的解决方案(文件名包含很多%)

《Java下载文件中文文件名乱码的解决方案(文件名包含很多%)》Java下载文件时,文件名中文乱码问题通常是由于编码不正确导致的,使用`URLEncoder.encode(filepath,UTF-8... 目录Java下载文件中文文件名乱码问题一般情况下,大家都是这样为了解决这个问题最终解决总结Java下

Idea实现接口的方法上无法添加@Override注解的解决方案

《Idea实现接口的方法上无法添加@Override注解的解决方案》文章介绍了在IDEA中实现接口方法时无法添加@Override注解的问题及其解决方法,主要步骤包括更改项目结构中的Languagel... 目录Idea实现接China编程口的方法上无法添加@javascriptOverride注解错误原因解决方

MYSQL事务死锁问题排查及解决方案

《MYSQL事务死锁问题排查及解决方案》:本文主要介绍Java服务报错日志的情况,并通过一系列排查和优化措施,最终发现并解决了服务假死的问题,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录问题现象推测 1 - 客户端无错误重试配置推测 2 - 客户端超时时间过短推测 3 - mysql 版本问

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Linux内存泄露的原因排查和解决方案(内存管理方法)

《Linux内存泄露的原因排查和解决方案(内存管理方法)》文章主要介绍了运维团队在Linux处理LB服务内存暴涨、内存报警问题的过程,从发现问题、排查原因到制定解决方案,并从中学习了Linux内存管理... 目录一、问题二、排查过程三、解决方案四、内存管理方法1)linux内存寻址2)Linux分页机制3)

IDEA运行spring项目时,控制台未出现的解决方案

《IDEA运行spring项目时,控制台未出现的解决方案》文章总结了在使用IDEA运行代码时,控制台未出现的问题和解决方案,问题可能是由于点击图标或重启IDEA后控制台仍未显示,解决方案提供了解决方法... 目录问题分析解决方案总结问题js使用IDEA,点击运行按钮,运行结束,但控制台未出现http://

数据库oracle用户密码过期查询及解决方案

《数据库oracle用户密码过期查询及解决方案》:本文主要介绍如何处理ORACLE数据库用户密码过期和修改密码期限的问题,包括创建用户、赋予权限、修改密码、解锁用户和设置密码期限,文中通过代码介绍... 目录前言一、创建用户、赋予权限、修改密码、解锁用户和设置期限二、查询用户密码期限和过期后的修改1.查询用