古道长亭

Contact me with ixiaoqiang0011@gmail.com


  • 首页

  • 归档

  • 分类

  • 关于

  • Book

  • 搜索

Netty高级应用

时间: 2022-07-24   |   分类: RPC框架   netty   | 字数: 3676 字 | 阅读约: 8分钟 | 阅读次数:

Netty高级应用

1.netty编解码器

1.1 java的编解码

  • 编码(Encode)称为序列化, 它将对象序列化为字节数组,用于网络传输、数据持久化或者其它用途。

  • 解码(Decode)称为反序列化,它把从网络、磁盘等读取的字节数组还原成原始对象(通常是原始对象的拷贝),以方便后续的业务逻辑操作。

java序列化对象只需要实现java.io.Serializable接口并生成序列化ID

Java序列化目的:1.网络传输。2.对象持久化。

Java序列化缺点:1.无法跨语言。 2.序列化后码流太大。3.序列化性能太低。

1.2 Netty编解码器

  • 概念

    在网络应用中需要实现某种编解码器,将原始字节数据与自定义的消息对象进行互相转换。网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码。

    对于Netty而言,编解码器由两部分组成:编码器、解码器。

    解码器:负责将消息从字节或其他序列形式转成指定的消息对象。

    编码器:将消息对象转成字节或其他序列形式在网络上传输。

    Netty 的编(解)码器实现了 ChannelHandlerAdapter,也是一种特殊的 ChannelHandler,所以依赖于 ChannelPipeline,可以将多个编(解)码器链接在一起,以实现复杂的转换逻辑。 Netty里面的编解码: 解码器:负责处理“入站 InboundHandler”数据。 编码器:负责“出站 OutboundHandler” 数据。

  • 解码器(Decoder)

    解码器负责 解码“入站”数据从一种格式到另一种格式,解码器处理入站数据是抽象ChannelInboundHandler的实现。需要将解码器放在ChannelPipeline中。对于解码器,Netty中主要提供了抽象基类ByteToMessageDecoder和MessageToMessageDecoder

    • ByteToMessageDecoder: 用于将字节转为消息,需要检查缓冲区是否有足够的字节
    • ReplayingDecoder: 继承ByteToMessageDecoder,不需要检查缓冲区是否有足够的字节,但是 ReplayingDecoder速度略慢于ByteToMessageDecoder,同时不是所有的ByteBuf都支持。项目复杂性高则使用ReplayingDecoder,否则使用ByteToMessageDecoder
    • MessageToMessageDecoder: 用于从一种消息解码为另外一种消息(例如POJO到POJO)

    示例代码:netty-demo codec

  • 编码器(Encoder)

    与ByteToMessageDecoder和MessageToMessageDecoder相对应,Netty提供了对应的编码器实现MessageToByteEncoder和MessageToMessageEncoder,二者都实现ChannelOutboundHandler接口。

    • MessageToByteEncoder: 将消息转化成字节
    • MessageToMessageEncoder: 用于从一种消息编码为另外一种消息(例如POJO到POJO)

    示例代码:netty-demo codec

  • 编码解码器Codec

    同时具有编码与解码功能,特点同时实现了ChannelInboundHandler和ChannelOutboundHandler接口,因此在数据输入和输出时都能进行处理。

    Netty提供提供了一个ChannelDuplexHandler适配器类,编码解码器的抽象基类 ByteToMessageCodec ,MessageToMessageCodec都继承与此类.

    示例代码:netty-demo codec

2.netty安全-群聊天室

要求:

  1. 编写一个 Netty 群聊系统,实现服务器端和客户端之间的数据简单通讯

  2. 实现多人群聊

  3. 服务器端:可以监测用户上线,离线,并实现消息转发功能

  4. 客户端:可以发送消息给其它所有用户,同时可以接受其它用户发送的消息

示例代码:netty-demo chat

3.基于Netty的Http服务器开发

Netty的HTTP协议栈无论在性能还是可靠性上,都表现优异,非常适合在非Web容器的场景下应用,相比于传统的Tomcat、Jetty等Web容器,它更加轻量和小巧,灵活性和定制性也更好。

功能需求:

  1. Netty 服务器在 8080 端口监听

  2. 浏览器发出请求 “http://localhost:8080/ "

  3. 服务器可以回复消息给客户端 “Hello! 我是Netty服务器 " ,并对特定请求资源进行过滤.

示例代码:netty-demo http

4.基于Netty的WebSocket开发网页版聊天室

4.1 websocket简介

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,客户端和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

应用场景

  1. 社交订阅

  2. 协同编辑/编程

  3. 股票基金报价

  4. 体育实况更新

  5. 多媒体聊天

  6. 在线教育

4.2 WebSocket和HTTP的区别

http协议是用在应用层的协议,他是基于tcp协议的,http协议建立连接也必须要有三次握手才能发送信息。 http连接分为短连接,长连接,短连接是每次请求都要三次握手才能发送自己的信息。即每一个request对应一个response。长连接是在一定的期限内保持连接。保持TCP连接不断开。客户端与服务器通信,必须要有客户端先发起, 然后服务器返回结果。客户端是主动的,服务器是被动的。

客户端要想实时获取服务端消息就得不断发送长连接到服务端.

WebSocket实现了多路复用,他是全双工通信。在webSocket协议下服务端和客户端可以同时发送信息。 建立了WebSocket连接之后, 服务端可以主动发送信息到客户端。而且信息当中不必在带有head的部分信息了与http的长链接通信来说,这种方式,

不仅能降低服务器的压力。而且信息当中也减少了部分多余的信息。

示例代码:netty-websocket-demo

5.Netty中粘包和拆包的解决方案

5.1 粘包和拆包简介

粘包和拆包是TCP网络编程中不可避免的,无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制。

TCP是个“流”协议,所谓流,就是没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

如图所示,假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下4种情况。

TCP粘包和拆包产生的原因:

数据从发送方到接收方需要经过操作系统的缓冲区,而造成粘包和拆包的主要原因就在这个缓冲区上。粘包可以理解为缓冲区数据堆积,导致多个请求数据粘在一起,而拆包可以理解为发送的数据大于缓冲区,进行拆分处理。

5.2 粘包拆包代码演示

  • 粘包

    示例代码:netty-demo stickybag

    可以看到,在注释掉粘包拆包解码器后,客户端发送10次,但服务端一次读取了客户端发送过来的消息,应该读取10次. 因此发生粘包.

  • 拆包

    示例代码:netty-demo unpacking

    可以看到,在注释掉粘包拆包解码器后, 当客户端发送的数据包比较大的时候, 客户端发送10次,但服务端读取了18次, 应该读取10次, 则发送拆包事件.

5.3 粘包和拆包的解决办法

  • 业内解决方案

    由于底层的TCP无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,可以归纳如下。

    • 消息长度固定,累计读取到长度和为定长LEN的报文后,就认为读取到了一个完整的信息
    • 将换行符作为消息结束符
    • 将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的结束分隔符
    • 通过在消息头中定义长度字段来标识消息的总长度
  • netty中的粘包和拆包解决方案

    Netty提供了4种解码器来解决

    • 固定长度的拆包器 FixedLengthFrameDecoder,每个应用层数据包都拆分成固定长度的大小
    • 行拆包器 LineBasedFrameDecoder,每个应用层数据包,都以换行符作为分隔符,进行分割拆分
    • 分隔符拆包器 DelimiterBasedFrameDecoder,每个应用层数据包,都通过自定义的分隔符,进行分割拆分
    • 基于数据包长度的拆包器 LengthFieldBasedFrameDecoder,将应用层数据包的长度,作为接收端应用层数据包的拆分依据。按照应用层数据包的大小,拆包。这个拆包器,有一个要求,就是应用层协议中包含数据包的长度
  • 代码实现

    • LineBasedFrameDecoder解码器

      ch.pipeline().addLast(new LineBasedFrameDecoder(2048));
      
      ctx.writeAndFlush(Unpooled.copiedBuffer("你好呀,我是Netty客户端"+i+"\n", CharsetUtil.UTF_8));
      
    • DelimiterBasedFrameDecoder解码器

      ByteBuf byteBuf = Unpooled.copiedBuffer("$".getBytes(StandardCharsets.UTF_8));
      ch.pipeline().addLast(new DelimiterBasedFrameDecoder(2048, byteBuf));
      
      ctx.writeAndFlush(Unpooled.copiedBuffer("你好呀,我是Netty客户端"+i+"$", CharsetUtil.UTF_8));
      
#rpc# #socket# #netty#
QQ扫一扫交流

标题:Netty高级应用

作者:古道长亭

声明: 欢迎加群交流!

如有帮助,欢迎多多交流 ^_^

微信打赏

支付宝打赏

Netty源码剖析
Netty核心原理
  • 文章目录
  • 站点概览
古道长亭

古道长亭

Always remember that your present situation is not your final destination. The best is yet to come.

226 日志
57 分类
104 标签
GitHub Gitee
友情链接
  • 古道长亭的BOOK
  • JAVA学习
标签云
  • Mysql
  • 搜索引擎
  • Mybatis
  • 容器
  • 架构
  • 消息队列
  • Flink
  • Sharding sphere
  • 流处理
  • 缓存
  • 1.netty编解码器
    • 1.1 java的编解码
    • 1.2 Netty编解码器
  • 2.netty安全-群聊天室
  • 3.基于Netty的Http服务器开发
  • 4.基于Netty的WebSocket开发网页版聊天室
    • 4.1 websocket简介
    • 4.2 WebSocket和HTTP的区别
  • 5.Netty中粘包和拆包的解决方案
    • 5.1 粘包和拆包简介
    • 5.2 粘包拆包代码演示
    • 5.3 粘包和拆包的解决办法
© 2019 - 2024 京ICP备19012088号-1
0%