下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、使用Netty军决TCP粘包和拆包问题过程详解刖百我们介绍了如果使用Netty来开发一个简单的服务端和客户端,接下来我们来讨论如何使用解码器来解决TCP的粘包和拆包问题TCP为什么会粘包拆包我们知道,TCP是以一种流的方式来进行网络转播的,当t三次握手简历通信后,客户端服务端之间就建立了一种通讯管道,我们可以想象成自来水管道,流出来的水是连城一片的,是没有分界线的。TCP底层并不了解上层的业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分。所以对于我们应用层而言。我们直观是发送一个个连续完整TCP数据包的,而在底层就可能会出现将一个完整的TCP拆分成多个包发送或者将多个包封装成一个
2、大的数据包发送。这就是所谓的TCP粘包和拆包。当发生TCP粘包拆包会发生什么情况我们举一个简单例子说明:客户端向服务端发送两个数据包:第一个内容为;第二个内容为。服务端接受一个数据并做相应的业务处理(这里就是打印接受数据加一个逗号)。那么服务端输出结果将会出现下面四种情况服务端响应结果结论12,345,6正常接收,没有发生粘包和拆包4异常接收,发生t粘包24,异常接收,发生t拆包25异常接收,发生t拆包和粘包如何解决主流的协议解决方案可以归纳如下:消息定长,例如每个报文的大小固定为个字节,如果不够,空位补空格;在包尾增加回车换行符进行切割;将消息分为消息头和消息体,消息头中包含表示消息总长度的
3、字段;更复杂的应用层协议。对于之刖描述的案例,在这里我们就可以采取方案1和方案3。以方案为例:我们每次发送的TCP包只有三个数字,那么我将报文设置为个字节大小的,此时,服务器就会以三个字节为基准来接受包,以此来解决站包拆包问题。Netty的解决之道LineBasedFrameDecoder废话不多说直接上代码服务端Pteettt配置服务端的N线程组et三=newNioetworkerGroeNtyeetteServerBootsteeNServerSocketChannel.cltCetSO_BACKLOG,.childHandler(newChildChannelHandler();/绑定端
4、口,同步等待成功ChannelFuturef=b.bind(port).sync();/等待服务端监听端口关闭f.channel().closeFuture().sync();finally/优雅退出,释放线程池资源bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();privateclassChildChannelHandlerextendsChannelInitializerOverrideprotectedvoidinitChannel(SocketChannelarg0)throwsExceptionarg0.p
5、ipeline().addLast(newLineBasedFrameDecoder(1024);/1arg0.pipeline().addLast(newStringDecoder();/2arg0.pipeline().addLast(newPrintServerHandler();publicstaticvoidmain(Stringargs)throwsExceptionintport=8080;newTimeServer().bind(port);服务端HandlerpublicclassPrintServerHandlerextendsChannelHandlerAdapterOv
6、erridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg)throwsExceptionByteBufbuf=(ByteBuf)msg;bytereq=newbytebuf.readableBytes();buf.readBytes(req);将缓存区的字节数组复制到新建的req数组中Stringbody=newString(req,UTF-8);System.out.println(body);Stringresponse=打印成功;ByteBufresp=Unpooled.copiedBuffer(response.get
7、Bytes();ctx.write(resp);OverridepublicvoidchannelReadComplete(ChannelHandlerContextctx)throwsExceptionctx.flush();OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause)ctx.close();客户端publicclassPrintClientpublicvoidconnect(intport,Stringhost)throwsExceptionEventLoopGroupgroup=new
8、NioEventLoopGroup();tryBootstrapb=newBootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true).handler(newChannelInitializer()OverridepublicvoidinitChannel(SocketChannelch)throwsExceptionch.pipeline().addLast(newLineBasedFrameDecoder(1024);/3ch.pipeline().addL
9、ast(newStringDecoder();/4ch.pipeline().addLast(newPrintClientHandler(););ChannelFuturef=b.connect(host,port).sync();f.channel().closeFuture().sync();finally/优雅退出,释放NIO线程组group.shutdownGracefully();/*paramargs*throwsException*/publicstaticvoidmain(Stringargs)throwsExceptionintport=8080;newTimeClient(
10、).connect(port,);客户端的HandlerpublicclassPrintClientHandlerextendsChannelHandlerAdapterprivatestaticfinalLoggerlogger=Logger.getLogger(TimeClientHandler.class.getName();privatefinalByteBuffirstMessage;/*Createsaclient-sidehandler.*/publicTimeClientHandler()bytereq=你好服务端.getBytes();firstMessage=Unpoole
11、d.buffer(req.length);firstMessage.writeBytes(req);OverridepublicvoidchannelActive(ChannelHandlerContextctx)ctx.writeAndFlush(firstMessage);OverridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg)throwsExceptionByteBufbuf=(ByteBuf)msg;bytereq=newbytebuf.readableBytes();buf.readBytes(req);Str
12、ingbody=newString(req,UTF-8);System.out.println(”服务端回应消息:+body);OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause)/释放资源System.out.println(Unexpectedexceptionfromdownstream:+cause.getMessage();ctx.close();上诉代码逻辑与上一章代码逻辑相同,客户端接受服务端数据答应,并回复客户端信息,客户端接受到数据后打印数据。我们观察代码可以发现,要想Netty解
13、决粘包拆包问题,只需在编写服务端和客户端的pipeline上加上相应的解码器即可,上诉注释1,2,3,4处。其余代码无需做任何修改。LineBasedFrameDecoder+StringDecoder的组合就是按行切换的文本解码器,它被设计用来支持TCP的粘包和拆包。原理为:如果连续读取到最大长度后任然没有发现换行符,就会抛出异常,同时忽略掉之前督导的异常码流。DelimiteBasedFrameDecoder该解码器的可以自动完成以分割符作为码流结束标识的消息解码。(其实上一个解码器类似,如果指定分隔符为换行符,那么与上一个编码器的作用基本相同)使用也很简单:只需要修改服务端和客户端对应代
14、码中的nitChanneI代码即可publicvoidinitChannel(SocketChannelch)ByteBufdeIimiter=UnpooIed.copiedBuffer(_.getBytes();/1ch.pipeline().addLast(newDelimiterBasedFrameDecoder(1024,delimiter);/2ch.pipeline().addLast(newStringDecoder();/3ch.pipeline().addLast(newPrintHandler();注释1:首先创建分隔符缓冲对象ByteBuf,并指定以作为分隔符。注释2:将分隔符缓冲对象ByteBuf传入DelimiterBasedFrameDecoder,并指定最大长度。注释3:指定为字符串字节流FixedLengthFrameDecoder该解码器为固定长度解码器,它能够按照指定的长度对详细进行自动解码。使用同样也很简单:同样只需要修改服务端和客户端对应代码中的nitChannel代码即可publicvoidinitChannel(SocketChannelch)throwsExceptionch.pipeline().addLast(newFixedLengthFrameDecode
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 建筑工程公司宿舍租赁合同
- 林业开发电力设施安装协议
- 医疗自建房施工合同模板
- 高级软件开发工程师聘用合同
- 员工生育援助政策手册
- 社会服务外网施工合同
- 城市绿化带养护植树合同
- 展览馆排水设施施工合同
- 商业活动策划用车租赁合同样本
- 珠宝行业合同专用章管理方案
- 办公室装修招标文件范本
- 超星尔雅学习通《当代大学生国家安全教育》章节测试答案
- 2024年广东省广州市白云区来穗人员服务管理局招聘历年高频难、易错点500题模拟试题附带答案详解
- GB/T 10433-2024紧固件电弧螺柱焊用螺柱和瓷环
- (新版)高级考评员职业技能鉴定考试题库(含答案)
- 项目农民工考勤管理制度
- 10.2+文化自信与文明交流互鉴【中职专用】高一思想政治《中国特色社会主义》(高教版2023基础模块)
- 专项训练:坐标的变化(30题)(原卷版+解析)
- 2024年新人教版一年级数学上册课件 第六单元 复习与关联 1.数与运算
- 中国华能招聘笔试题库2024
- 七年级上册《朝花夕拾》梳理及真题训练(含答案)
评论
0/150
提交评论