Netty4.x 的逆袭之路 —— 再识 Netty

Netty4.x 的逆袭之路

2020年9月25日 Netty 结合 protobuf 使用

预习

在netty数据传输过程中可以有很多选择,比如;字符串、json、xml、java对象,但为了保证传输的数据具备;良好的通用性、方便的操作性和传输的高性能,我们可以选择protobuf作为我们的数据传输格式。

protobuf Google开发的一个数据格式

202 案例跑通 (失败)

总结

202:

  1. 该篇主要讲述 protobuf 传输数据格式在 Netty 中的应用,
    protobuf 需要自行下载源码编译. 因为考虑环境时间等原因. 该章节案例暂时过掉
    这里有 32 位操作系统的, 但是我的环境是 64 位. 不能执行.

2020年9月25日 Netty传输Java对象

预习

Netty在实际应用级开发中,有时候某些特定场景下会需要使用Java对象类型进行传输,

但是如果使用Java本身序列化进行传输,那么对性能的损耗比较大。

为此我们需要借助protostuff-core的工具包将对象以二进制形式传输并做编码解码处理。

与直接使用protobuf二进制传输方式不同,这里不需要定义proto文件,而是需要实现对象类型编码解码器,用以传输自定义Java对象。

protostuff 基于Google protobuf,但是提供了更多的功能和更简易的用法。其中,protostuff-runtime 实现了无需预编译对java bean进行protobuf序列化/反序列化的能力。protostuff-runtime的局限是序列化前需预先传入schema,反序列化不负责对象的创建只负责复制,因而必须提供默认构造函数。此外,protostuff 还可以按照protobuf的配置序列化成json/yaml/xml等格式。在性能上,protostuff不输原生的protobuf,甚至有反超之势。

  1. 支持protostuff-compiler产生的消息
  2. 支持现有的POJO对象
  3. 支持现有的protoc产生的Java消息
  4. 与各种移动平台的互操作能力(Android、Kindle、j2me)
  5. 支持转码

203 案例跑通


2020-09-25 18:25:28 接收到消息类型:class cc.lvgo.netty4x.netty_intermediate.netty203.domain.MsgInfo
2020-09-25 18:25:28 接收到消息内容:MsgInfo[channelId='4c1bee9e', msgContent='I'm coming , 加入中文, 检测乱码']

总结

203:

  1. fasjson 异常 : create asm serializer error 原因是包路径有中文导致.

  2. 加深了对编解码的认识. 编码解码器可以算是一个核心功能了, 正是有了它的存在, 使得 IO 操作更加强大.
    同时 Netty 本身内置了超多编解码器. 赞, 他太强了

  3. 同时本节关键其实在于 SerializationUtil 的内容. protostuff

画个重点

  • protostuff 基于Google protobuf,但是提供了更多的功能和更简易的用法。其中,protostuff-runtime 实现了无需预编译对java bean进行protobuf序列化/反序列化的能力。protostuff-runtime的局限是序列化前需预先传入schema,反序列化不负责对象的创建只负责复制,因而必须提供默认构造函数。此外,protostuff 还可以按照protobuf的配置序列化成json/yaml/xml等格式。在性能上,protostuff不输原生的protobuf,甚至有反超之势。

2020年9月26日 Netty 使用 protosutff 实现断点续传

预习

传输文件需要注意的一些内容

  1. 文件

204 案例跑通

2020-09-26 12:44:33 bugstack虫洞栈服务端,接收客户端传输文件请求。FileDescInfo[fileUrl='D:\game\1234567.tft', fileName='1234567.tft', fileSize=222696]
102400
2020-09-26 12:44:55 bugstack虫洞栈服务端,接收客户端传输文件请求[断点续传]。FileBurstInstruct[clientFileUrl='D://game/1234567.tft', readPosition=102401, status=1]
102400
2020-09-26 12:45:11 bugstack虫洞栈服务端,接收客户端传输文件请求[断点续传]。FileBurstInstruct[clientFileUrl='D://game/1234567.tft', readPosition=204802, status=1]
17894


// 断开过3次  208 kb 的文件 一次传输 100 kb
客户端连接成功, 远程地址 : /127.0.0.1:2333
2020-09-26 12:45:11 bugstack虫洞栈客户端传输文件信息。 FILE:1234567.tft SIZE(byte):17894
服务端断开连接, /127.0.0.1:2333

总结

204:

  1. 通过这个案例明白了断点传输的原理, 同时也看到了 protostuff 的强大!

  2. 对Netty之间的传输更加的清晰了一些. server client 编解码 . 读取, 回写.
    通道、管道、注册、拦截

    建立一根通道,注册一系列管道。通道拦截分配给不同的管道处理,最后又存通道流出。

2020年9月26日 Netty 与 websocket 的结合

预习

一个简单的聊天页面 - 模仿微信聊天网页版哦

Netty的应用方面非常广;聊天、MQ、RPC、数据等等

emm… 不是我说傅哥, 他英语是真的不好
public ChannelFuture bing(InetSocketAddress address)

205 案例跑通

2020-09-26 17:03:02.160  INFO 18140 --- [ntLoopGroup-3-5] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 33, cap: 128))
2020-09-26 17:03:19.937  INFO 18140 --- [ntLoopGroup-3-5] c.l.n.n.netty205.server.MyServerHandler  : /192.168.31.93:52203 断开了连接
2020-09-26 17:03:20.042  INFO 18140 --- [ntLoopGroup-3-6] c.l.n.n.netty205.server.MyServerHandler  : 有一个客户端连接了 : /192.168.31.93:52209
2020-09-26 17:03:20.080  INFO 18140 --- [ntLoopGroup-3-6] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":1,"msgInfo":"请求个人信息"}
2020-09-26 17:03:20.080  INFO 18140 --- [ntLoopGroup-3-6] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 33, cap: 128))
2020-09-26 17:03:33.762  INFO 18140 --- [ntLoopGroup-3-3] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"787989787"}
2020-09-26 17:03:33.765  INFO 18140 --- [ntLoopGroup-3-3] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed))
2020-09-26 17:03:47.721  INFO 18140 --- [ntLoopGroup-3-2] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"咕咕咕咕咕咕"}
2020-09-26 17:03:47.724  INFO 18140 --- [ntLoopGroup-3-2] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed))
2020-09-26 17:04:36.330  INFO 18140 --- [ntLoopGroup-3-2] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"接受"}
2020-09-26 17:04:36.332  INFO 18140 --- [ntLoopGroup-3-2] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed))
2020-09-26 17:04:36.594  INFO 18140 --- [ntLoopGroup-3-6] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"xixi\n\n"}
2020-09-26 17:04:36.595  INFO 18140 --- [ntLoopGroup-3-6] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed))
2020-09-26 17:04:41.690  INFO 18140 --- [ntLoopGroup-3-2] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"😁"}
2020-09-26 17:04:41.691  INFO 18140 --- [ntLoopGroup-3-2] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 76, cap: 256))
2020-09-26 17:04:53.091  INFO 18140 --- [ntLoopGroup-3-6] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"hello\n"}
2020-09-26 17:04:53.092  INFO 18140 --- [ntLoopGroup-3-6] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed))
2020-09-26 17:05:02.282  INFO 18140 --- [ntLoopGroup-3-3] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"😁😁😁😁"}
2020-09-26 17:05:02.284  INFO 18140 --- [ntLoopGroup-3-3] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed))
2020-09-26 17:05:11.626  INFO 18140 --- [ntLoopGroup-3-3] c.l.n.n.netty205.server.MyServerHandler  : 服务端收到:{"type":2,"msgInfo":"红红火火恍恍惚惚哈哈嚯嚯嚯哈哈\n阿时间打款拉数据的卡了吉拉斯大苏打水"}
2020-09-26 17:05:11.628  INFO 18140 --- [ntLoopGroup-3-3] c.l.n.n.netty205.server.MyServerHandler  : 回复客户端 : TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(freed))

总结

205:

  1. Netty 实现与 websocket 通信的过程东西还是比较多, 但整个过程还是比较清晰. 建立连接, 发送消息 -> 根据消息类型处理消息. 结合之前的 ChannelGroup 知识, 这里以群发为案例进行开发
  2. 每种通讯里面其实最重要的还是编解码器
        channel.pipeline().addLast("http-codec", new HttpServerCodec());
        channel.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
        channel.pipeline().addLast("http-chunked", new ChunkedWriteHandler());

这里应该是第一次解出来 netty-handler 包. 之前一直打交道的是 netty-transportnetty-common

2020年9月27日 Netty 与 elasticsearch 的结合

预习

206 案例失败

2020-09-28 07:41:17.284  INFO 11444 --- [ntLoopGroup-3-2] o.l.n.n.netty206.server.MyServerHandler  : 有一个客户端连接了 : /127.0.0.1:10240
2020-09-28 07:41:17.729  INFO 11444 --- [ntLoopGroup-3-2] o.l.n.n.netty206.server.MyServerHandler  : {"address":"北京","age":1,"email":"184172133@qq.com","entryDate":1601250077286,"id":"34e7a034-fe59-4eb0-aacd-e73c1b96d01b","level":"T0-1","mobile":"13566668888","name":"李小明"}
2020-09-28 07:41:18.225 ERROR 11444 --- [ntLoopGroup-3-2] o.l.n.n.netty206.server.MyServerHandler  : 服务端异常

io.netty.handler.codec.DecoderException: java.lang.IllegalStateException: Reading from a byte array threw an IOException (should never happen).

206 案例成功

2020-09-29 10:03:21.312  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : 有一个客户端连接了 : /127.0.0.1:64990
2020-09-29 10:03:21.758  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"北京","age":1,"email":"184172133@qq.com","entryDate":1601345001073,"id":"8aa1dc11-57c2-43e3-8658-dbaac27cec56","level":"T0-1","mobile":"13566668888","name":"李小明"}
2020-09-29 10:03:22.396  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"南京","age":2,"email":"huahua@qq.com","entryDate":1601345001073,"id":"66b5acd6-a3bc-4705-bd5a-43ba243e9211","level":"T0-2","mobile":"13566660001","name":"张大明"}
2020-09-29 10:03:22.827  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"榆树","age":2,"email":"xiaobai@qq.com","entryDate":1601345001073,"id":"8379cca2-57db-4e01-bf10-753ebf920cad","level":"T1-1","mobile":"13566660002","name":"李书鹏"}
2020-09-29 10:03:23.364  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"榆树","age":2,"email":"xiaobai@qq.com","entryDate":1601345001073,"id":"4a00fa8a-598e-4679-bad4-321bf3e59b9b","level":"T2-1","mobile":"13566660002","name":"韩小雪"}
2020-09-29 10:03:23.943  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"河北","age":2,"email":"xiaobai@qq.com","entryDate":1601345001073,"id":"e79ac12c-2c61-47e3-a53f-d2e3deba9de8","level":"T4-1","mobile":"13566660002","name":"董叔飞"}
2020-09-29 10:03:24.459  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"下花园","age":2,"email":"xiaobai@qq.com","entryDate":1601345001073,"id":"731bdc90-6c9a-4b33-bc18-562b3b338221","level":"T5-1","mobile":"13566660002","name":"候明相"}
2020-09-29 10:03:24.855  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"东平","age":2,"email":"xiaobai@qq.com","entryDate":1601345001073,"id":"7c6f6b70-29f7-4fd7-b8e2-7604b37f9a54","level":"T3-1","mobile":"13566660002","name":"田明明"}
2020-09-29 10:03:25.295  INFO 9564 --- [ntLoopGroup-3-1] o.l.n.n.netty206.server.MyServerHandler  : {"address":"西湖","age":2,"email":"xiaobai@qq.com","entryDate":1601345001074,"id":"e542aff7-0d41-44b0-9131-4342fd4be314","level":"T4-1","mobile":"13566660002","name":"王大伟"}

总结

206:

  1. 当 elasticsearch 服务所在磁盘内存超过可用内存 95% 时, 索引被设置为只读.

  2. 一直出现的一个异常, 偶尔只能存到 elasticsearch 里面一条记录, 之后就会报出这个异常.

io.netty.handler.codec.DecoderException: java.lang.IllegalStateException: Reading from a byte array threw an IOException (should never happen).
  1. 问题解决, 原因是在解码器中读取的字节数值取错, 同时延伸出一个问题. 解码器时如何反复处理一个长包, 1200个字节, 一次取固定的长度. 是如何将这1200个字节全部取完的呢? 递归?

2020年9月28日 Netty 请求响应同步通信

预习

207 案例跑通

09:27:12.663 [nioEventLoopGroup-4-1] INFO org.lvgo.netty4x.netty_intermediate.netty207.server.RpcServerChannelHandler - 客户端请求参数: {"param":"查询{bugstack虫洞栈}用户信息","requestId":"bd127648-82c8-434c-be51-bfbc1906cfd4"}
09:27:12.663 [nioEventLoopGroup-4-1] INFO org.lvgo.netty4x.netty_intermediate.netty207.server.RpcServerChannelHandler - 服务端返回 : {"result":"服务端返回的结果只是一堆字符串而已","requestId":"bd127648-82c8-434c-be51-bfbc1906cfd4"}
09:27:12.664 [nioEventLoopGroup-4-1] INFO org.lvgo.netty4x.netty_intermediate.netty207.server.RpcServerChannelHandler - 通道读完之后, 不刷新通道
09:27:12.664 [main] INFO org.lvgo.netty4x.netty_intermediate.netty207.client.RpcClientTest - 调用结果: {"result":"服务端返回的结果只是一堆字符串而已","requestId":"bd127648-82c8-434c-be51-bfbc1906cfd4"}

总结

207:

  1. 多练, 代码不是说出来背出来的. 是敲出来的. 渐渐的明白好记性不如烂笔头的道理. 坚持编码. 才能编码. 理论为基础. 实践见真理.
  2. channelReadComplete 方法中 调用通道 context 的 flush 有什么用?

2020年9月29日 Netty 之 心跳检测和重连处理

预习

如何保证客户端(服务端)是否在线? 发现断开的重连如何解决?

208 案例跑通

1:20:15.554 [nioEventLoopGroup-13-1] INFO org.lvgo.netty4x.netty_intermediate.netty208.client.HeartbeatClientHandler - connection server successful!
11:20:17.562 [nioEventLoopGroup-14-1] INFO org.lvgo.netty4x.netty_intermediate.netty208.client.HeartbeatClientHandler - connection server successful!
11:20:19.571 [nioEventLoopGroup-15-1] INFO org.lvgo.netty4x.netty_intermediate.netty208.client.HeartbeatClientHandler - connection server successful!
11:20:21.580 [nioEventLoopGroup-16-1] INFO org.lvgo.netty4x.netty_intermediate.netty208.client.HeartbeatClientHandler - connection server successful!
11:20:23.604 [nioEventLoopGroup-17-1] INFO org.lvgo.netty4x.netty_intermediate.netty208.client.HeartbeatClientHandler - connection server successful!

1:20:19.572 [nioEventLoopGroup-3-6] INFO org.lvgo.netty4x.netty_intermediate.netty208.server.HeartbeatServerHandler - /127.0.0.1:51434 is connected
11:20:20.472 [nioEventLoopGroup-3-1] INFO org.lvgo.netty4x.netty_intermediate.netty208.server.HeartbeatServerHandler - Idle state : READER_IDLE
11:20:20.474 [nioEventLoopGroup-3-4] INFO org.lvgo.netty4x.netty_intermediate.netty208.server.HeartbeatServerHandler - Idle state : READER_IDLE
11:20:20.511 [nioEventLoopGroup-3-7] INFO org.lvgo.netty4x.netty_intermediate.netty208.server.HeartbeatServerHandler - Idle state : READER_IDLE
11:20:20.536 [nioEventLoopGroup-3-2] INFO org.lvgo.netty4x.netty_intermediate.netty208.server.HeartbeatServerHandler - Idle state : READER_IDLE

总结

208:

  1. 心跳机制实现使用到了 IdleStateHandler , 放在服务端用来检测设置阈值内是否有数据进行传输. 如果达到了空闲阈值, 进行事件方法调用.
  2. 模拟重连使用了 ChannelFutureListener 异步回调和 EventLoop schedule 周期执行
  3. 心跳和重连 : 客户端定时发送心跳包, 服务端定时检查心跳包. 客户端发现断连后 在 channelInActive 方法中进行尝试重新连接.

2020年9月29日 Netty 之 集群通信

预习

  • 跨服务之间案例采用redis的发布和订阅进行传递消息,如果你是大型服务可以使用zookeeper
  • 用户A在发送消息给用户B时候,需要传递B的channeId,以用于服务端进行查找channeId所属是否自己的服务内
  • 单台机器也可以启动多个Netty服务,程序内会自动寻找可用端口

209 案例跑通

2020-09-29 17:42:20 接收到消息内容:{"content":"hi! ","toChannelId":"3a2d5cee"}
2020-09-29 17:42:20.827  INFO 16820 --- [ntLoopGroup-3-3] o.l.n.n.netty209.server.MyServerHandler  : 接收消息的用户不在本服务端,PUSH!
2020-09-29 17:42:20.831  INFO 16820 --- [    container-8] o.l.n.n.n.redis.MsgAgreementReceiver     : 接收到PUSH消息:{"content":"hi! ","toChannelId":"3a2d5cee"}

总结

209:

  1. 基于 redis 实现 netty 集群通信原理其实比较简单. 建立连接后将通道 id 和 通道 channel 保存在本服务器中. 接收到消息时检查是否为本服务内通道. 是则发送消息, 否则推送到 redis 中, 由 redis 通知给全员进行寻址.

2020年9月29日 Netty 之 多协议通信

预习

一个服务端响应多个客户端发来的不同协议消息时, 如何处理?

210 案例跑通

2:12:50.228 [nioEventLoopGroup-3-1] INFO org.lvgo.netty4x.netty_intermediate.netty210.server.MultipleProtocolServer - 客户端接收到信息: {"date":1601388769869,"id":"3f1e5a9d","command":1,"content":"77665544332211"}
22:12:50.236 [nioEventLoopGroup-3-1] INFO org.lvgo.netty4x.netty_intermediate.netty210.server.MultipleProtocolServer - 客户端接收到信息: {"date":1601388769880,"id":"3f1e5a9d","command":2,"content":"第二类"}
22:12:50.252 [nioEventLoopGroup-3-1] INFO org.lvgo.netty4x.netty_intermediate.netty210.server.MultipleProtocolServer - 客户端接收到信息: {"date":1601388769880,"id":"3f1e5a9d","command":3,"content":456788}

总结

210:

  1. 本章节内容主要为多协议数据传输的处理, 整体学习思路较为清晰. 定义好不同的协议标准, 针对不同的协议进行不同的逻辑处理
  2. 引入了一个新的抽象类 SimpleChannelInboundHandler 可以指定读取数据类型. 随后需对此类进行深入学习理解.

2020年9月30日 Netty 基于 ChunkedStream 数据流切块传输

预习

在Netty这种异步NIO框架的结构下,服务端与客户端通信过程中,高效、频繁、大量的写入大块数据时,因网络传输饱和的可能性就会造成数据处理拥堵、GC频繁、用户掉线的可能性。那么由于写操作是非阻塞的,所以即使没有写出所有的数据,写操作也会在完成时返回并通知ChannelFuture。当这种情况发生时,如果仍然不停地写入,就有内存耗尽的风险。所以在写大块数据时,需要对大块数据进行切割发送处理。

ChunkedStream 分块流. 分包发送?

https://netty.io/4.0/api/io/netty/handler/stream/ChunkedStream.html ChunkedInput 的实现 ChunkedFile 从文件中逐块获取数据,当你的平台不支持零拷贝或者你需要转换数据时使用 ChunkedNioFile 和ChunkedFile 类似,只是它使用了FileChannel ChunkedStream 从InputStream 中逐块传输内容 ChunkedNioStream 从ReadableByteChannel 中逐块传输内容

211 案例跑通

总结

211:

无。 该知识点仅做了解。未对内容进行总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值