资讯专栏INFORMATION COLUMN

Netty3文档翻译(二)

Zhuxy / 3184人阅读

摘要:丰富的缓存数据结构使用它自己的缓存来表示字节序列而不是的。针对有一个定义良好的事件模型。有一些协议是多层的建立在其他低级协议基础上。此外,甚至不是完全线程安全的。协议由标准化为。协议缓存整合是一个高效二进制协议的快速实现。

Chapter 2、结构概览

这一节我们将确认Netty提供的核心功能是什么,以及它们怎么构成一个完整的网络应用开发堆栈。

1、丰富的缓存数据结构

Netty使用它自己的缓存API来表示字节序列而不是NIO的ByteBuffer。Netty的新缓存类——ChannelBuffer,彻底解决了ByteBuffer的问题,满足了网络应用开发者的日常需求。这里列举几个很酷的特点:

需要的话你可以自定义缓存类

通过一个内置的组合缓存类实现零拷贝组合

提供开箱即用的动态缓存,自动扩容,就像StringBuffer一样

不再需要调用flip方法

通常比ByteBuffer要快

组合和切分ChannelBuffer

当在通信层传输数据时,数据经常需要被组合或者切分。比如一次装载被分成多个包,但是经常需要组合起来解码。
传统方式来说,多个包的数据通过复制到一个新的字节缓存而组合起来。
Netty支持零复制实现,通过让一个新的ChannelBuffer“指向”所有要求组合的缓存,从而避免了复制操作。

2、统一异步I/O API

传统Java的I/O API对不同的传输类型提供不同的类和方法。举个例子,java.net.Socket和java.net.DatagramSocket没有公共父类因此它们在执行socket I/O的方式完全不一样。

这种不匹配的结果就是使得应用程序从一种传输方式移植成另一种变得十分困难。也就是说你需要支持额外的传输方式因为应用程序的网络层经常涉及到重写。逻辑上,许多协议可以在不只一种传输方式,比如TCP/IP、UDO/IP、SCTP和串行通信上运行。

更糟的是,Java的新I/O(NIO)API继承了老阻塞I/O(OIO)API的不兼容性,并且在下一个版本NIO.2(AIO)继续这样做。因为这些API在设计和表现特点上完全不同,你经常被迫在应用程序开始实现之前就需要确定好依赖那种API。

举个例子,你可能想用OIO方式开始因为你服务的客户数量很小且用OIO写一个socket服务比用NIO要简单得多。但是,当你的业务呈指数级上升然后你需要同时服务成千上万的客户时,麻烦就大了。你也可以用NIO方式开始,但是这可能会阻碍开发速度,毕竟NIO的选择器API很复杂。

Netty拥有统一的异步I/O接口——Channel,它抽象了点对点通信要求的所有操作。只要你用一种Netty传输写的应用程序,可以在其他Netty传输上运行。Nett通过统一的API提供了必要的传输方式:

基于NIO的TCP/IP传输(见org.jboss.netty.channel.socket.nio)

基于OIO的TCP/IP传输(见org.jboss.netty.channel.socket.oio)

基于OIO的UDP/IP传输

本地传输(见org.jboss.netty.channel.local)

要从一种传输方式切换到另一种,只需要改动几行代码,比如选择另一个ChannelFactory实现。

你甚至可以使用还没发布的新传输方式,比如串行通信传输,同样替换几行构造器调用的代码。再者,你也可以通过继承核心API实现自己的传输方式。

3、基于过滤链模式的事件模型

一个定义良好的并可扩展性高的事件模型是一个事件驱动应用程序的前提。Netty针对I/O有一个定义良好的事件模型。你可以在不破坏已有代码的情况下实现你自己的事件类,因为每一个事件类都根据一个严格的类层次体系区别于其他事件类。这是另一个和其他框架的不同点。很多NIO框架都没有或者很有限的事件模型概念。如果它们提供了扩展,就会经常在尝试增加自定义事件类时破坏已有代码。

一个ChannelEvent由一个ChannelPipeline里的一列ChannelHandler来处理。这个管道实现了一个过滤链模式的高级形式,让使用者完全控制一个事件如何被处理以及管道内的handler如何相互联系。举个例子,你可以规定数据从socket读取时做点什么:

public class MyReadHandler implements SimpleChannelHandler {
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent evt) {
        Object message = evt.getMessage();
        // Do something with the received message.
        ...
        // And forward the event to the next handler.
        ctx.sendUpstream(evt);
    }
}

你也可以规定一个handler在接收一个写请求时做点什么:

public class MyWriteHandler implements SimpleChannelHandler {
    public void writeRequested(ChannelHandlerContext ctx, MessageEvent evt) {
        Object message = evt.getMessage();
        // Do something with the message to be written.
        ...
        // And forward the event to the next handler.
        ctx.sendDownstream(evt);
    }
}
4、支持更快速开发的高级组件 4.1、编解码框架

之前“用POJO替代ChannelBuffer”那一节证实了,把协议编解码从业务逻辑中分离出来通常是一个好主意。但是从零开始实现有一些困难。你需要处理信息分片。有一些协议是多层的(建立在其他低级协议基础上)。还有一些协议在单机系统上实现特别困难。

因此,一个好的网络应用框架需要提供一个可扩展的、可重用的、可单元测试的和多层级的编解码器框架,产生可维护的用户编解码器。

Netty提供了一系列基础和高级的编解码器,可以解决你在写一个协议编解码器是遭遇的大多数问题,无论编解码器是否简单,是二进制的还是文本的。

4.2、SSL/TLS支持

不像阻塞I/O,在NIO支持SSL是个值得正视对任务。你不能简单得包装一个流对数据进行加密解密,你必须要用到javax.net.ssl.SSLEngine。SSLEngine是一个跟SSL本身一样复杂的状态机。你需要处理所有可能的状态,如密码套件、加密密钥协商、证书交换以及验证。此外,SSL甚至不是完全线程安全的。

在Netty,SslHandler负责对外屏蔽SSLEngine所有细枝末节,你只需要配置SslHandler然后添加到你的ChannelPipeline中。SslHandler同时让你可以很容易实现类似StartTLS的高级特性。

4.3、HTTP实现

HTTP绝对是互联网最流行的协议。现在已经有一系列HTTP实现,比如Servlet容器。那么为什么Netty还要自己实现HTTP呢?

Netty的HTTP支持和现有的HTTP库很不一样。它让你可以完全控制HTTP在底层的消息交换。因为从根本上来说,它就是一个HTTP编解码器和HTTP消息类的结合,没有类似强制线程模型这样的限制。也就是说,你可以按照你希望的工作方式来实现HTTP客户端和服务端。你拥有所有HTTP规范内的控制权,包括线程模型、连接生命周期和分块编码。

基于它的高可定制性,你可以写一个高效的HTTP服务:

要求持续连接和服务推送技术的聊天服务(如Comet);

需要保持连接直到整个媒体文件流传输完毕的媒体流服务(如两小时的电影);

无内存压力上传大文件的文件服务(如上传1G文件);

可以异步连接成千上万的第三方web服务的可伸缩的混合客户端

4.4、WebSocket实现

WebSocket在单TCP socket上实现一个双向全双工通信通道,用于web浏览器和web服务端端数据交互。
WebSocket协议由IETF标准化为RFC 6455。
Netty实现了RFC 6455和一系列旧版本规范。

4.4、Google协议缓存整合

Google Protocal Buffers是一个高效二进制协议的快速实现。凭借ProtobufEncoder和ProtobufDecoder,你可以将Goodgle Protocal Buffers编译程序生成的信息类转化为Netty编解码器。

5、总结

这一节,我们从特点出发回顾了Netty的总体架构。Netty拥有一个简单且至今仍强大的架构。它由三个组件组成——buffer,channel和事件模型,所有高级特性都是在这三个组件的基础上建立的。只要你理解了这三个组件是如何一起工作的,你就不难理解这节简要提及的那些高级特性。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74242.html

相关文章

  • Netty3文档翻译(一)

    摘要:但是它不是自己创建线程,而是从调用构造方法时指定的线程池中获取线程。这就意味着,即使发送两个独立的消息,操作系统会把他们视为一个字节串。释放过程很简单,调用它的方法,所有相关的和线程池将会自动关闭。 简单找了下发现网上没有关于Netty3比较完整的源码解析的文章,于是我就去读官方文档,为了加强记忆,翻译成了中文,有适当的简化。 原文档地址:Netty3文档 Chapter 1 开始 1...

    sherlock221 评论0 收藏0
  • 少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

    摘要:的选择器允许单个线程监视多个输入通道。一旦执行的线程已经超过读取代码中的某个数据片段,该线程就不会在数据中向后移动通常不会。 1、引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典IO(也就是常说的阻塞式IO)的API时,很快就会发现一个问题:我什么时候应该使用经典IO,什么时候应该使用NIO? 在本文中,将尝试用简明扼要的文字,阐明Java NIO和经典IO之...

    Meils 评论0 收藏0
  • dubbo源码解析(一)Hello,Dubbo

    摘要:英文全名为,也叫远程过程调用,其实就是一个计算机通信协议,它是一种通过网络从远程计算机程序上请求服务而不需要了解底层网络技术的协议。 Hello,Dubbo 你好,dubbo,初次见面,我想和你交个朋友。 Dubbo你到底是什么? 先给出一套官方的说法:Apache Dubbo是一款高性能、轻量级基于Java的RPC开源框架。 那么什么是RPC? 文档地址:http://dubbo.a...

    evin2016 评论0 收藏0
  • React文档翻译系列()Hello World

    摘要:文档翻译系列二开始最简单的方式就是在上使用示例。最小的例子如下它会在页面上渲染一个标题。接下来的几部分会逐步的介绍如何使用。我们会查验应用的构建块元素和组件。在例子中也使用了一些的语法。可以使用在线转换器查看的代码编译。 React文档翻译系列(二)Hello World Hello World 开始React最简单的方式就是在CodePen上使用Hello World示例。无需安装任...

    Mertens 评论0 收藏0
  • 干货|人人都是翻译项目的Master

    摘要:开始翻译函数式编程专有名词库在翻译的过程中,难免会遇到很多描述不太清楚的专有名词,一个办法是小组内进行讨论,最后商量出来结果,小组内统一翻译。因为本书的主题是函数式编程,所以这个名词库里大部分都是函数式编程相关的专有名词。 在平时的工作中,我们都会经常查阅一些英文文档来解决平时遇到的问题和拓宽视野。看到好的文章或者书籍有没有想要和小伙伴分享的冲动,那么我们一起来翻译吧~ 翻译主张 信 ...

    kyanag 评论0 收藏0

发表评论

0条评论

阅读需要支付1元查看
<