Netty 入门

1. 粘包问题

一 .长连接与短连接:

1.长连接:Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收。长连接在 netty 中是默认开启的,也就是我们创建了一个 Server 以后监听端口,我们的客户端去连接发现只要我们的客户端不主动的断开连接他们之间的连接是一直保持有效的。 2.短连接:Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此种方式常用于一点对多点通讯,比如多个Client连接一个Server。但是在 netty 中默认采用了长连接,我们如何使用短连接呢?其实很简单,在我们的 Server 端需要对客户端进行回写数据的时候我们只需要在回写的后面加上一个监听事件,就是当写完毕,我们就关闭此连接。

ctx.channel().writeAndFlush("Hi Client I'm Server !&&").addListener(ChannelFutureListener.CLOSE);

二 .什么时候需要考虑粘包问题?

1:如果利用tcp每次发送数据,就与对方建立连接,然后双方发送完一段数据后,就关闭连接,这样就不会出现粘包问题,因为只有一种包结构,类似于http协议。 2:如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包 3:如果双方建立连接,需要在连接后一段时间内发送不同结构数据,则需要考虑粘包问题。

三 .粘包出现原因

TCP 是一个字节流的的传输,也就是在流中传输无固定结构的数据包。但是UDP不会出现粘包,因为它有消息边界。 1 发送端需要等缓冲区满才发送出去,造成粘包 2 接收方不及时接收缓冲区的包,造成多个包接收

具体的在 TCP 中出现这种情况的原因:

  1. 由Nagle算法造成的发送端的粘包:Nagle算法是一种改善网络传输效率的算法.简单的说,当我们提交一段数据给TCP发送时,TCP并不立刻发送此段数据,而是等待一小段时间,看看在等待期间是否还有要发送的数据,若有则会一次把这两段数据发送出去.这是对Nagle算法一个简单的解释,详细的请看相关书籍.
  2. 接收端接收不及时造成的接收端粘包:TCP会把接收到的数据存在自己的缓冲区中,然后通知应用层取数据.当应用层由于某些原因不能及时的把TCP的数据取出来,就会造成TCP缓冲区中存放了几段数据. 四 .解决办法 为了避免粘包现象,可采取以下几种措施:
  3. 一是对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满;
  4. 二是对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象;
  5. 三是由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。

   以上提到的三种措施,都有其不足之处。第一种编程设置方法虽然可以避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议使用。第二种方法只能减少出现粘包的可能性,但并不能完全避免粘包,当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包。第三种方法虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。

   最初遇到”粘包”的问题时,我是通过在两次send之间调用sleep来休眠一小段时间来解决.这个解决方法的缺点是显而易见的,使传输效率大大降低,而且也并不可靠.后来就是通过应答的方式来解决,尽管在大多数时候是可行的,但是不能解决象B的那种情况,而且采用应答方式增加了通讯量,加重了网络负荷. 再后来就是对数据包进行封包和拆包的操作.    封包:封包就是给一段数据加上包头,这样一来数据包就分为包头和包体两部分内容了(以后讲过滤非法包时封包会加入”包尾”内容).包头其实上是个大小固定的结构体,其中有个结构体成员变量表示包体的长度,这是个很重要的变量,其他的结构体成员可根据需要自己定义.根据包头长度固定以及包头中含有包体长度的变量就能正确的拆分出一个完整的数据包.

五 .在 netty 中解决粘包的方式

  1. 采用了分隔符,类似于链路层的那种使用一个特殊的标记来分割数据,这里主要采用了一个工具类 DelimiterBasedFrameDecoder(arg0,agr1) 其中第一个参数指的是这个分隔符的可占用的空间大小,只能比他大不能小于。第二个参数就是具体的分隔符了,但是不能传递一个字符串而是一个 ByteBuf 对象,也就是我们需要用工具转一下 Unpooled.copiedBuffer("&&".getBytes()) ,代码如下:
pipeline.addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer("&&".getBytes())));
  1. 第二种方式也比较简单,这个就是采用了定长的报文,当我们的报文长度不够的时候必须要采用空格补齐。比如说,我们发送了 “aaaaacc” 而我们的定长指定的是 5 那么,我们只会收到 “aaaaa” 而没有 c 这就是因为他不足 5 个,我们必须采用空格补齐才能收到,或者等待下次数据比较多的时候会跟着过来。
.addLast(new FixedLengthFrameDecoder(5));
  1. pojo 方式,也就是自定义数据的头和体部分,其中头中最重要的就是一个长度字段。

参考资料:

  • https://blog.csdn.net/zhangxinrun/article/details/6721495

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java 源码分析

Netty 入门

1. 粘包问题 一 .长连接与短连接: 1.长连接:Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收。长连接在 net...

3937
来自专栏along的开发之旅

Android逆向分析概述

学习逆向的初衷是想系统学习Android下的hook技术和工具, 想系统学习Android的hook技术和工具是因为Android移动性能实战这本书. 这本书里...

8094
来自专栏MixLab科技+设计实验室

设计师编程指南之Sketch插件开发 1

发现网上关于sketch插件开发的指南太少了,而且都不一定可以成功运行,于是我就写了这个系列的文章: 1 我们需要了解的语法特点 sketch 是基于 Coc...

6598
来自专栏后端技术探索

网络安全之【XSS和XSRF攻击】

XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性。...

2043
来自专栏三丰SanFeng

Linux同步机制 - 基本概念(死锁,活锁,饿死,优先级反转,护航现象)

死锁(deadlock) 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态...

3289
来自专栏涤生的博客

天池中间件大赛——单机百万消息队列存储设计与实现

这次天池中间件性能大赛初赛和复赛的成绩都正好是第五名,本次整理了复赛《单机百万消息队列的存储设计》的思路方案分享给大家,实现方案上也是决赛队伍中相对比较特别的。

2161
来自专栏码匠的流水账

聊聊jdbc的大数据量读写相关异常的防御措施

jdbc提供fetchSize参数来设置每次查询按fetchSize分批获取。不同的数据库的jdbc driver实现不一样。

1631
来自专栏高性能服务器开发

(六)关于网络编程的一些实用技巧和细节

这些年,接触了形形色色的项目,写了不少网络编程的代码,从windows到linux,跌进了不少坑,由于网络编程涉及很多细节和技巧,一直想写篇文章来总结下这方面的...

3937
来自专栏码神联盟

碎片化 | 第四阶段-40-Struts组件分类讲解-视频

如清晰度低,可转PC网页观看高清版本: http://v.qq.com/x/page/o0567s4azx0.html ---- ---- 版权声明:本视频...

3469
来自专栏小曾

.Net Web开发技术栈

有很多朋友有的因为兴趣,有的因为生计而走向了.Net中,有很多朋友想学,但是又不知道怎么学,学什么,怎么系统的学,为此我以我微薄之力总结归纳写了一篇.Net w...

4003

扫码关注云+社区

领取腾讯云代金券