java read非阻塞_Java NIO知识点整理(四) 如何设计一个非阻塞服务

前面几个章节了解到了对于NIO来说几个重要点组建:Selector、Channel、Buffer,但是真正去设计一个通信组建还是很困难的,比如比较出名的通信框架Netty是通过多个Pipelines(管道)组件链来处理非阻塞的IO。

一、一个最简单的非阻塞IO Pipeline设计理念

非阻塞IO管道可以使用一个线程从多个流读取消息。在非阻塞模式下,当您试图从流中读取数据时,流可能返回0或更多字节。如果流没有要读取的数据,则返回0字节。当流实际上有一些数据要读取时,返回1+字节。

为了避免检查需要读取0字节的流,我们使用Java NIO选择器。可以使用选择器注册一个或多个SelectableChannel实例。当您在选择器上调用select()或selectNow()时,它只给您一个SelectableChannel实例,该实例实际上具有要读取的数据。

1、读取数据

在上面我们就知道了,我们可以通过一个流管道,将读取的数据进行传递,但是怎样知道读取的数据是完整的呢?当数据不完整时,如何将已经读取的数据存下来,并且应该分配多少内存进行存储,在我们处理一个消息体时,面临两个问题:检测数据是否时完整的

如何处理部分数据,在剩余消息完整到达前

检测消息的完整性,可以用消息阅读器进行检测,如果消息时完整的,则将消息通过管道投递到下游进行处理,对于部分消息来说,需要使用Buffer来存储,直到剩余消息到达前。

在检索到要从选择器读取数据的通道实例之后,与该通道关联的消息读取器将读取数据并尝试将其分解为消息。如果这导致读取任何完整的消息,则可以将这些消息通过读取管道传递到需要处理它们的任何组件。

消息阅读器当然是特定于协议的。消息阅读器需要知道它要读取的消息的消息格式。如果我们的服务器实现要跨协议重用,它需要能够插入消息阅读器实现——可能通过以某种方式接受消息阅读器工厂作为配置参数。

2、存储部分消息

既然我们已经确定了在接收到完整消息之前存储部分消息是消息阅读器的职责,那么我们需要弄清楚应该如何实现该部分消息存储。

我们需要考虑两个设计因素:我们希望尽可能少地复制消息数据。复制越多,性能越低。

我们希望完整的消息以连续的字节序列存储,以便更容易地解析消息。

这时候我们需要用到Buffer了,然而,这个缓冲区应该有多大?它需要足够大,甚至能够存储允许的最大消息。因此,如果允许的最大消息是1MB,那么每个消息阅读器中的内部缓冲区至少需要1MB。有以下几种方式:可调整大小的缓冲区

采用复制的方式

动态追加

TLV消息编码:一些协议消息格式使用TLV格式(类型、长度、值)编码。这意味着,当消息到达时,消息的总长度存储在消息的开头。这样就可以立即知道要为整个消息分配多少内存。

如需了解更多的内容,大家可以关注我公众号“聊点源码”,获取更多资讯。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值