由Netty引出对协议的思考

协议到底是什么?

之前我们接触过很多协议,最熟悉莫过于HTTP、TCP、DUBBO 那么到底是什么是协议,又和Netty、TCP、SOCKET有何关系?

协议:两端约定好的一种字节数组结构,

应用层协议:例如前8个字节表示消息类型 后8个字节代表总数据的长度,由于现在都是使用面向对象语言编程,那么如何将业务对象数据转换成网络传输的字节,已经将字节反序列化成对象。目前用的比较多方式有json序列化,java的对象序列化,protobuf,hessian,xml形式。 发送数据端按照约定俗成方式编码,那么接受端就以同样方式进行解码。 这种协议就是应用层协议。

传输层协议:tcp协议是可靠、面向报文段的传输协议,tcp报文头+应用层的字节数据 保证数据传给某台主机对应的端口号的进程进行处理

网络层协议:ip头+tcp报文数据 保证该数据传给指定ip的主机

数据链路层和物理层

下发消息时每经过一层协议就会加上该层的头部信息,在接受消息时每经过一层协议就会去掉头部信息,最终会在传输层被接受,然后通过socket(获取tcp层数据的工具)拿到数据,然后根据不同的应用层协议(定义的不同字节结构)进行解析到应用层所有使用的数据(字节),然后解码(json、protobuf)成业务对象

Socket可以看作是获取tcp层数据或向tcp写入数据的工具

Netty可以看作成socket框架,用该框架可以做自定义协议(通过实现ChannelHandler的编码器和解码器)的服务器和客户端,同时可以处理高并发的连接(非阻塞I/O),面向事件驱动开发(自定义实现ChannelHandler进行监听Channel的某种事件)

编解码器

之所以Netty能实现各种应用层协议 例如HTTP、FTP、WebSocket 或自定义的协议,就是编解码器起到的作用。

编码器:将业务对象转换成某种特定格式的字节数组(例如 头部+消息体(将对象转换成字节称为序列化(JSON、ProtoBuf、java对象序列化))),进行网络传输

解码器:接收到网络传输的二进制字节数组,通过对应的解码器转化成业务所使用的对象,只不过是上面的逆过程

tcp层只关心传输的二进制数据,所以会将应用层的数据划分成多个报文段,所以通过Netty获取tcp中的数据可能是拆包的或者粘包的。以下Netty定义的几种解决此问题的方法:

1、固定长度数据

也就是网络上传输的数据都是统一长度的数据

2、分隔符

通常采用\r\n方式来区分传输的数据,当然也可以自定义分隔符

3、头部+消息体

头部:一般固定好长度, 存放消息类型,消息体大小
具体消息内容:大小就等于头部定义的大小

HTTP协议采用 分隔符+头部、消息体结合的方式传输的数据

Netty编解码实现

由于应用层数据在传输层会拆成各个小报文段,还有netty又是异步的,所以在解码时候需要对接受的数据进行缓存直到解码成最终需要的结果。

得益于Netty的易扩展性,可以通过增加对应的ChannelHandler实现就能完成某种功能,同样编解码器也实现了ChannelInBound和ChannelOutBound接口

编解码器的基础实现类,其他都是继承该基类

抽象模板设计模式

ByteToMessageDecoder:从字节转化业务对象

实现该抽象方法 decode(ChannelHandlerContext ctx, ByteBuf in, List out)
out存放解码后对象

可能一开始不满足解码条件,可以缓存起来,例如需要头部字节数为10,也就是可读字节数>=10时,才进行解析

MessageToMessageDecoder:从消息对象A解码成另外一种消息对象B

decode(ChannelHandlerContext ctx, I msg, List out) I:表示输入对象A 然后解码成另外一种对象B存放到out中

MessageToByteEncoder:将业务对象转换成字节

encode(ChannelHandlerContext ctx, I msg, ByteBuf out) I:就是输入的业务对象转换成特定格式的字节数组对象传给out

MessageToMessageEncoder:从消息对象B编码另外一种消息对象A

encode(ChannelHandlerContext ctx, I msg, List out) I:表示输出对象B 然后解码成另外一种对象A存放到out中

源码实习借鉴处

1、将CodecOutputList (也是实现了List接口) 放在ThreadLocal中保证线程安全

2、使用对象池将CodecOutputList缓存起来,避免了重复创建对象开销和节省内存资源

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty是一个高性能的网络通信框架,可以用于将Modbus协议与网络进行对接。Modbus是一种通信协议,常用于工业领域的设备间通信。下面是一个简单的示例,展示如何使用Netty对接Modbus协议。 首先,你需要引入Netty和Modbus相关的依赖。可以在项目的构建文件(例如pom.xml)中添加以下依赖: ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.63.Final</version> </dependency> <dependency> <groupId>de.gandev</groupId> <artifactId>modbus-client</artifactId> <version>2.1.0</version> </dependency> ``` 接下来,你可以创建一个Netty的客户端来连接Modbus设备。以下是一个简单的示例代码: ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import de.gandev.modjdatabus.ModbusTcpClient; import de.gandev.modjdatabus.ModbusTcpClientHandler; public class ModbusClient { private final String host; private final int port; public ModbusClient(String host, int port) { this.host = host; this.port = port; } public void run() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap() .group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); // 添加Modbus协议处理器 pipeline.addLast(new ModbusTcpClientHandler()); } }); // 连接Modbus设备 ChannelFuture future = bootstrap.connect(host, port).sync(); Channel channel = future.channel(); // 发送Modbus命令 byte[] command = new byte[]{0x01, 0x03, 0x00, 0x00, 0x00, 0x01, (byte) 0x84, (byte) 0x0A}; channel.writeAndFlush(command); // 等待连接关闭 future.channel().closeFuture().sync(); } finally { // 关闭连接 group.shutdownGracefully(); } } public static void main(String[] args) throws Exception { String host = "192.168.0.1"; int port = 502; ModbusClient client = new ModbusClient(host, port); client.run(); } } ``` 在上述示例中,我们首先创建了一个`ModbusTcpClientHandler`,它是一个Netty的ChannelHandler,用于处理Modbus协议的请求和响应。然后,我们使用Netty的`Bootstrap`来设置客户端的配置和处理器。最后,我们连接Modbus设备并发送Modbus命令。 请注意,以上只是一个简单的示例,实际的Modbus通信可能涉及更多的细节和配置。你可以根据具体的需求进行修改和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值