精华内容
下载资源
问答
  • Netty框架学习之(三):细说Netty的数据传输1. 概述2. API说明3. 内置的传输方式3.1 NIO3.2 Epoll3.3 OIO3.4 Local3.5 Embedded 1. 概述 使用Java 自带的API开发IO系统时,如果需要对传输的方式进行切换,例如从阻塞...

    1. 概述

    使用Java 自带的API开发IO系统时,如果需要对传输的方式进行切换,例如从阻塞传输切换到非阻塞传输, 那么可能会由于两种方式的API不兼容问题需要大面积的修改代码。然而 Netty 则为它所有的传输方式提供了一个通用 API,这使得只需要修改一下对象申明的类型就能完成传输方式的切换,例如从OIO切换到NIO只需要如下操作:

    OIO的代码:
    EventLoopGroup group = new OioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(group)
                        .channel(OioServerSocketChannel.class)
                .........
            } finally {
                group.shutdownGracefully().sync();
            }
    
    NIO的代码:
    EventLoopGroup group = new NioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(group)
                        .channel(NioServerSocketChannel.class)
                .........
            } finally {
                group.shutdownGracefully().sync();
            }
    
    

    是不是很方便?

    2. API说明

    传输API的核心Channel,它被用于所有的IO操作,Channel的类图如下所示:
    在这里插入图片描述
    如图所示,每个 Channel 都将会被分配一个 ChannelPipeline 和 ChannelConfig。
    ChannelConfig 包含了该 Channel 的所有配置设置,并且支持热更新.

    由于 Channel 是独一无二的,所以为了保证顺序将 Channel 声明为 java.lang.
    Comparable 的一个子接口。因此,如果两个不同的 Channel 实例都返回了相同的散列码,那么 AbstractChannel 中的 compareTo()方法的实现将会抛出一个 Error.

    ChannelPipeline 持有所有将应用于入站和出站数据以及事件的 ChannelHandler 实
    例,这些 ChannelHandler 实现了应用程序用于处理状态变化以及数据处理的逻辑,例如:

    • 将数据从一种格式转换为另一种格式;
    • 提供异常的通知;
    • 提供 Channel 变为活动的或者非活动的通知;
    • 提供当 Channel 注册到 EventLoop 或者从 EventLoop 注销时的通知;
    • 提供有关用户自定义事件的通知。

    也可以根据需要通过添加或者移除ChannelHandler实例来修改ChannelPipeline,通过利用Netty的这项能力可以构建出高度灵活的应用程序。

    3. 内置的传输方式

    Netty内置了多种类型的传输方式,不同的传输方式有不同的应用场景与支持的协议,目前常见的类型包括以下几种

    3.1 NIO

    NIO类型的传输提供了一个所有 I/O 操作的全异步的实现,主要利用了自JAVA 自带 NIO 子系统的选择器API。

    3.2 Epoll

    	Netty 的 NIO 传输基于 Java 提供的异步/非阻塞网络编程的通用抽象。虽然这保证了 Netty 的非阻塞 API 可以在任何平台上使用,但它也包含了相应的限制,因为 JDK为了在所有系统上提供相同的功能,必须做出妥协。
    	Epoll自Linux内核版本 2.5.44(2002)被引入,提供了比旧的POSIX select和poll系统调用更好的性能。如果你的应用程序旨在运行于Linux系统,那么可以考虑利用这个版本的传输;你将发现在高负载下它的性能要优于JDK的NIO实现
    

    3.3 OIO

    Netty 的 OIO 传输实现代表了一种折中:它可以通过常规的传输 API 使用,但是由于它
    是建立在 java.net 包的阻塞实现之上的,所以它不是异步的。但是,它仍然非常适合于某些用途。例如,你可能需要移植使用了一些进行阻塞调用的库(如JDBC)的遗留代码,而将逻辑转换为非阻塞的可能也是不切实际的。相反,你可以在短期内使用Netty的OIO传输,然后再将你的代码移植到纯粹的异步传输上。

    Netty是如何能够使用和用于异步传输相同的API来支持OIO的呢?
    答案就是, Netty利用了SO_TIMEOUT这个Socket标志,它指定了等待一个I/O操作完成的最大毫秒数。如果操作在指定的时间间隔内没有完成, 则将会抛出一个SocketTimeout Exception。 Netty将捕获这个异常并继续处理循环。在EventLoop下一次运行时,它将再次尝试。这实际上也是类似于Netty这样的异步框架能够支持OIO的唯一方式。

    3.4 Local

    Netty 提供了一个 Local 传输,用于在同一个 JVM 中运行的客户端和服务器程序之间的异步通信。

    在同一个 JVM 内部的通信,不需要通过网络暴露服务,是
    Local 传输的完美用例。这将消除所有真实网络操作的开销,同时仍然使用你的 Netty 代码库。如果随后需要通过网络暴露服务,那么你将只需要把传输改为 NIO 或者 OIO 即可。

    3.5 Embedded

    如果你想要为自己的 ChannelHandler 实现编
    写单元测试,可以考虑使用 Embedded 传输。这既便于测试你的代码,而又不需要创建大
    量的模拟(mock)对象。你的类将仍然符合常规的 API 事件流, 保证该 ChannelHandler
    在和真实的传输一起使用时能够正确地工作。

    自己学习使用,摘录

    展开全文
  • Netty传输数据传输API

    2018-03-22 11:24:31
    Java 开发网络程序传输数据的过程和方式是被抽象了的,我们不需要关注底层接口,只需要使用 Java API 或其他网络框架Netty 就能达到传输数据的目的。发送数据和接收数据都是字节码。Nothingmore,nothing less。...

    网络应用程序一个很重要的工作是传输数据。传输数据的过程不一样取决是使用哪种交通工具,但是传输的方式是一样的:都是以字节码传输。Java 开发网络程序传输数据的过程和方式是被抽象了的,我们不需要关注底层接口,只需要使用 Java API 或其他网络框架如 Netty 就能达到传输数据的目的。发送数据和接收数据都是字节码。Nothingmore,nothing less。

    Netty传输API 
    传输 API 的核心是 Channel 接口,它用于所有出站的操作。Channel 接口的类层次结构如下: 
    这里写图片描述

    如上图所示,每个 Channel 都会分配一个 ChannelPipeline 和 ChannelConfig。 
    ChannelConfig 负责设置并存储配置,并允许在运行期间更新它们。传输一般有特定的配置设置,只作用于传输,没有其他的实现。ChannelPipeline 容纳了使用的 ChannelHandler实例,这些 ChannelHandler 将处理通道传递的“入站”和“出站”数据。 
    ChannelHandler 的实现允许你改变数据状态和传输数据,ChannelHandler 是 Netty 的重点概念。

    现在我们可以使用 ChannelHandler 做下面一些事情:

    • 传输数据时,将数据从一种格式转换到另一种格式
    • 异常通知
    • Channel 变为有效或无效时获得通知
    • Channel 被注册或从 EventLoop 中注销时获得通知
    • 通知用户特定事件

    这些 ChannelHandler 实例添加到 ChannelPipeline 中,在 ChannelPipeline 中按顺序逐个执行。它类似于一个链条。 
    ChannelPipeline 实现了拦截过滤器模式, 这意味着我们连接不同的 ChannelHandler来拦截并处理经过 ChannelPipeline 的数据或事件。可以把 ChannelPipeline 想象成 UNIX管道,它允许不同的命令链(ChannelHandler 相当于命令)。你还可以在运行时根据需要添加 ChannelHandler 实例到 ChannelPipeline 或从 ChannelPipeline 中删除,这能帮助我们构建高度灵活的 Netty 程序。此外,访问指定的 ChannelPipeline 和 ChannelConfig,你能在 Channel 自身上进行操作。Channel 提供了很多方法,如下列表:

    • eventLoop(),返回分配给 Channel 的 EventLoop
    • pipeline(),返回分配给 Channel 的 ChannelPipeline
    • isActive(),返回 Channel 是否激活,已激活说明与远程连接对等
    • localAddress(),返回已绑定的本地 SocketAddress
    • remoteAddress(),返回已绑定的远程 SocketAddress
    • write(),写数据到远程客户端,数据通过 ChannelPipeline 传输过去

    Netty 包含的传输实现

    Netty 自带了一些传输协议的实现,虽然没有支持所有的传输协议,但是其自带的已足够我们来使用。Netty 应用程序的传输协议依赖于底层协议,本节我们将学习 Netty 中的传输协议。

    Netty 中的传输方式有如下几种:

    • NIO,io.netty.channel.socket.nio,基于 java.nio.channels 
      的工具包,使用选择器作为基础的方法。
    • OIO,io.netty.channel.socket.oio,基于 java.net 的工具包,使用阻塞流。
    • Local,io.netty.channel.local,用来在虚拟机之间本地通信。
    • Embedded,io.netty.channel.embedded,嵌入传输,它允许在没有真正网络的运输中使用 ChannelHandler,可以非常有用的来测试 ChannelHandler 的实现。

    NIO - Nonblocking I/O

    NIO 传输是目前最常用的方式, 它通过使用选择器提供了完全异步的方式操作所有的I/O,NIO 从 Java 1.4 才被提供。NIO 中,我们可以注册一个通道或获得某个通道的改变的状态,通道状态有下面几种改变:

    • 一个新的 Channel 被接受并已准备好
    • Channel 连接完成
    • Channel 中有数据并已准备好读取
    • Channel 发送数据出去

    处理完改变的状态后需重新设置他们的状态,用一个线程来检查是否有已准备好的Channel,如果有则执行相关事件。在这里可能只同时一个注册的事件而忽略其他的。选择器所支持的操作在 SelectionKey 中定义,具体如下:

    • OP_ACCEPT,有新连接时得到通知
    • OP_CONNECT,连接完成后得到通知
    • OP_READ,准备好读取数据时得到通知
    • OP_WRITE,写入数据到通道时得到通知

    Netty 中的 NIO 传输就是基于这样的模型来接收和发送数据,通过封装将自己的接口提供给用户使用,这完全隐藏了内部实现。如前面所说,Netty 隐藏内部的实现细节,将抽象出来的 API 暴露出来供使用,下面是处理流程图: 
    这里写图片描述 
    NIO 在处理过程也会有一定的延迟,若连接数不大的话,延迟一般在毫秒级,但是其吞吐量依然比 OIO 模式的要高。Netty 中的 NIO 传输是“zero-file-copy”,也就是零文件复制,这种机制可以让程序速度更快, 更高效的从文件系统中传输内容, 零复制就是我们的应用程序不会将发送的数据先复制到 JVM 堆栈在进行处理,而是直接从内核空间操作。接下来我 
    们将讨论 OIO 传输,它是阻塞的。

    OIO - Old blocking I/O

    OIO 就是 java 中提供的 Socket 接口,java 最开始只提供了阻塞的 Socket,阻塞会导致程序性能低。下面是 OIO的处理流程图

    Local - In VM transport

    Netty 包含了本地传输,这个传输实现使用相同的 API 用于虚拟机之间的通信,传输是完全异步的。 每个 Channel 使用唯一的 SocketAddress, 客户端通过使用 SocketAddress进行连接,在服务器会被注册为长期运行,一旦通道关闭,它会自动注销,客户端无法再使用它。 连接到本地传输服务器的行为与其他的传输实现几乎是相同的, 需要注意的一个重点是只能在本地的服务器和客户端上使用它们。Local 未绑定任何 Socket,值提供 JVM 进程之间的通信。

    Embedded transport

    Netty 还包括嵌入传输, 与之前讲述的其他传输实现比较, 它是不是一个真的传输呢?若不是一个真的传输,我们用它可以做什么呢?Embedded transport 允许更容易的使用不同的 ChannelHandler 之间的交互,这也更容易嵌入到其他的 ChannelHandler 实例并像一个辅助类一样使用它们。它一般用来测试特定的 ChannelHandler 实现,也可以在ChannelHandler 中重新使用一些 ChannelHandler 来进行扩展,为了实现这样的目的,它 自带了一个具体的 Channel 实现,即:EmbeddedChannel。

    每种传输的使用时机

    • OIO,在低连接数、需要低延迟时、阻塞时使用
    • NIO,在高连接数时使用
    • Local,在同一个 JVM 内通信时使用
    • Embedded,测试 ChannelHandler 时使用
    展开全文
  • Netty框架学习之(一):Netty框架简介

    万次阅读 多人点赞 2018-05-23 18:43:19
    官方定义为:”Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器 和客户端”,按照惯例贴上一张High Level的架构图: 纵观Java系的多种服务器/大数据框架,都离不...

    1. 简介

    官方定义为:”Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器
    和客户端”,按照惯例贴上一张High Level的架构图:

    这里写图片描述

    纵观Java系的多种服务器/大数据框架,都离不开Netty做出的贡献,本文对Netty做一个简单的概述

    2. 主要特性

    Netty有很多重要的特性,主要特性如下:
    - 优雅的设计
    - 统一的API接口,支持多种传输类型,例如OIO,NIO
    - 简单而强大的线程模型
    - 丰富的文档
    - 卓越的性能
    - 拥有比原生Java API 更高的性能与更低的延迟
    - 基于池化和复用技术,使资源消耗更低
    - 安全性
    - 完整的SSL/TLS以及StartTLS支持
    - 可用于受限环境,如Applet以及OSGI

    Netty的以上特性,比较适合客户端数据较大的请求/处理场景,例如web服务器等,要想知道有哪些系统使用了Netty,可以参考:http://netty.io/wiki/adopters.html

    3. 主要术语

    在正式开始之前,先对Netty涉及到的一些术语做个简单的说明

    3.1 IO模型:BIO/NIO/Netty

    3.1.1 BIO(Blocking IO):阻塞IO

    早期的Java API(java.net)提供了由本地系统套接字库提供的所谓的阻塞函数,样例代码如下:

    ServerSocket serverSocket = new ServerSocket(portNumber);
    Socket clientSocket = serverSocket.accept();
    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    PrintWriter out =new PrintWriter(clientSocket.getOutputStream(), true);
    String request, response;
    while ((request = in.readLine()) != null) {
        if ("Done".equals(request)) {
            break;
    }
    response = processRequest(request);
    out.println(response);
    }
    

    这段代码片段将只能同时处理一个连接,要管理多个并发客户端,需要为每个新的客户端
    Socket 创建一个新的 Thread,线程模型如下图所示:

    这里写图片描述

    该种模型存在以下两个问题:
    1. 在任何时候都可能有大量的线程处于休眠状态,只是等待输入或者输出数据就绪,这可能算是一种资源浪费
    2. 需要为每个线程的调用栈都分配内存
    3. 即使 Java 虚拟机(JVM) 在物理上可以支持非常大数量的线程, 但是远在到达该极限之前, 上下文切换所带来的开销就会带来麻烦

    3.1.2 NIO(Non Blocking IO):非阻塞IO

    Java的NIO特性在JDK 1.4中引入,其结构如下:

    这里写图片描述

    从该图可以看出Selector 是Java 的非阻塞 I/O 实现的关键。它使用了事件通知 API
    以确定在一组非阻塞套接字中有哪些已经就绪能够进行 I/O 相关的操作。因为可以在任何的时间检查任意的读操作或者写操作的完成状态。该种模型下,一个单一的线程便可以处理多个并发的连接。
    与BIO相比,该模型有以下特点:
    1. 使用较少的线程便可以处理许多连接,因此也减少了内存管理和上下文切换所带来开销
    2. 当没有 I/O 操作需要处理的时候,线程也可以被用于其他任务

    虽然Java 的NIO在性能上比BIO已经相当的优秀,但是要做到如此正确和安全并
    不容易。特别是,在高负载下可靠和高效地处理和调度 I/O 操作是一项繁琐而且容易出错的任务,此时就时Netty上场的时间了。

    3.1.3 Netty

    Netty对NIO的API进行了封装,通过以下手段让性能又得到了一定程度的提升
    1. 使用多路复用技术,提高处理连接的并发性
    2. 零拷贝:
    1. Netty的接收和发送数据采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝
    2. Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象进行一次操作
    3. Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题
    3. 内存池:为了减少堆外直接内存的分配和回收产生的资源损耗问题,Netty提供了基于内存池的缓冲区重用机制
    4. 使用主从Reactor多线程模型,提高并发性
    5. 采用了串行无锁化设计,在IO线程内部进行串行操作,避免多线程竞争导致的性能下降
    6. 默认使用Protobuf的序列化框架
    7. 灵活的TCP参数配置

    详细说明,可参考: http://www.infoq.com/cn/articles/netty-high-performance#anch111813

    3.1.4 简单的性能测试

    通过在本地分别使用BIO,NIO,Netty NIO实现了一个简单的服务端程序(该程序接收到请求后,sleep 1毫秒,并返回简单的一句话)分别对三种方式使用Jemeter进行性能测试(一百个并发,每个并发发送一百个相同消息),结果如下:

    单线程的java net:

    这里写图片描述

    NIO:
    这里写图片描述

    Netty NIO:
    这里写图片描述

    以上结果或是受到其他条件的影响,结果仅供供参考

    3.2 Callback:

    回调在广泛的编程场景中都有应用,一般是在完成某个特定的操作后对相关方法进行调用。

    Netty 在内部使用回调来处理事件;当一个回调被触发时,相关的事件可以被一个 interfaceChannelHandler 的实现处理,例如Channel激活时会调用ChannelActive方法,样例代码如下:

    public class ConnectHandler extends ChannelInboundHandlerAdapter {
    @Override
        public void channelActive(ChannelHandlerContext ctx)throws Exception {
            System.out.println("Client " + ctx.channel().remoteAddress() + connected");
    
        }
    }

    3.3 Future:

    Future一般用在当执行异步操作时需要获取未来的某个时候才能获取到的结果。

    JDK 预置了 interface java.util.concurrent.Future,但是其所提供的实现,只
    允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以 Netty提供了它自己的实现——ChannelFuture,用于在执行异步操作的时候使用。

    ChannelFuture提供了几种额外的方法,这些方法使得我们能够注册一个或者多个
    ChannelFutureListener实例。监听器的回调方法operationComplete(),将会在对应的
    操作完成时被调用。然后监听器可以判断该操作是成功地完成了还是出错了。如果是后者,我们可以检索产生的Throwable。 通过使用ChannelFutureListener机制可以避免对
    操作结果进行手动检查。

    每个 Netty 的出站 I/O 操作都将返回一个ChannelFuture,即不会阻塞后续的操作。

    下面的例子中的connect()方法会直接返回,后续的成功或失败将由其注册的FutureListener来处理。

            try {
                // 使用异步的方式连接Server,不管成功失败,都是执行下面System.out的语句,最后的连接结果由FutureListener进行处理
                ChannelFuture future = bootstrap.connect();
                System.out.println("Finished connect operation");
                future.addListener((ChannelFutureListener) future1 -> {
                    if (future1.isSuccess()){
                        ByteBuf buffer = Unpooled.copiedBuffer(
                                "Hello", Charset.defaultCharset());
                        ChannelFuture wf = future1.channel()
                                .writeAndFlush(buffer);
                        System.out.println("Connect successful!");
                    }else{
                        System.out.println("Connect failed!");
                        Throwable cause = future1.cause();
                        cause.printStackTrace();
                    }
                });
                System.out.println("Finished connect operation2");
                future.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    

    最后的打印结果如下:

    Finished connect operation
    Finished connect operation2
    Connect failed!
    io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/127.0.0.1:8888
        at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
        at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:325)
        at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect
        ...............................................
        Caused by: java.net.ConnectException: Connection refused: no further information
        ... 11 more

    3.4 Event

    Netty 使用不同的事件来通知状态的改变或者是操作的状态。事件可能包括:
    - 连接已被激活或者连接失活
    - 数据读取;
    - 用户事件;
    - 错误事件。
    - 打开或者关闭到远程节点的连接;
    - 将数据写到或者冲刷到套接字。

    每个事件都可以被分发给 ChannelHandler 类中的某个用户实现的方法。这是将事件驱动范式直接转换为应用程序逻辑处理比较理想的位置。
    下图展示了事件是怎么被处理的:

    这里写图片描述

    对每个事件可以进行,记录日志,数据转换,应用程序逻辑处理等操作,

    Netty 提供了大量预定义的可以开箱即用的 ChannelHandler 实现,包括用于各种协议
    (如 HTTP 和 SSL/TLS)的 ChannelHandler。后续博文会对一些Handler进行简单的介绍

    展开全文
  • 流经网络的数据总是具有相同的类型:字节,这些字节如何传输主要取决于我们所说的网络传输。用户并不关心传输的细节,只在乎字节是否被可靠地发送和接收 如果使用 Java 网络编程,你会发现,某些时候当你需要支持高...

    概述

    流经网络的数据总是具有相同的类型:字节,这些字节如何传输主要取决于我们所说的网络传输。用户并不关心传输的细节,只在乎字节是否被可靠地发送和接收

    如果使用 Java 网络编程,你会发现,某些时候当你需要支持高并发连接,随后你尝试将阻塞传输切换为非阻塞传输,那么你会因为这两种 API 的截然不同而遇到问题。Netty 提供了一个通用的 API,这使得转换更加简单。


    传统的传输方式

    这里介绍仅使用 JDK API 来实现应用程序的阻塞(OIO)和非阻塞版本(NIO)

    阻塞网络编程如下:

    public class PlainOioServer {
    
        public void server(int port) throws IOException {
            // 将服务器绑定到指定端口
            final ServerSocket socket = new ServerSocket(port);
            try {
                while (true) {
                    // 接收连接
                    final Socket clientSocket = socket.accept();
                    System.out.println("Accepted connection from " + clientSocket);
                    // 创建一个新的线程来处理连接
                    new Thread(() -> {
                        OutputStream out;
                        try {
                            out = clientSocket.getOutputStream();
                            // 将消息写给已连接的客户端
                            out.write("Hi\r\n".getBytes(StandardCharsets.UTF_8));
                            out.flush();
                            // 关闭连接x
                            clientSocket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                clientSocket.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    这段代码可以处理中等数量的并发客户端,但随着并发连接的增多,你决定改用异步网络编程,但异步的 API 是完全不同的

    非阻塞版本如下:

    public class PlainNioServer {
    
        public void server(int port) throws IOException {
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.configureBlocking(false);
            ServerSocket ssocket = serverChannel.socket();
            InetSocketAddress address = new InetSocketAddress(port);
            // 将服务器绑定到选定的端口
            ssocket.bind(address);
            // 打开 Selector 来处理 Channel
            Selector selector = Selector.open();
            // 将 ServerSocket 注册到 Selector 以接受连接
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
            final ByteBuffer msg = ByteBuffer.wrap("Hi\r\n".getBytes());
            while (true) {
                try {
                    // 等待需要处理的新事件,阻塞将一直持续到下一个传入事件
                    selector.select();
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }
                Set<SelectionKey> readKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = readKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    try {
                        // 检查事件是否是一个新的已经就绪可以被接受的连接
                        if (key.isAcceptable()) {
                            ServerSocketChannel server = (ServerSocketChannel) key.channel();
                            SocketChannel client = server.accept();
                            client.configureBlocking(false);
                            // 接受客户端,并将它注册到选择器
                            client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, msg.duplicate());
                            System.out.println("Accepted connection from " + client);
                        }
                        // 检查套接字是否已经准备好写数据
                        if (key.isWritable()) {
                            SocketChannel client = (SocketChannel) key.channel();
                            ByteBuffer buffer = (ByteBuffer) key.attachment();
                            while (buffer.hasRemaining()) {
                                // 将数据写到已连接的客户端
                                if (client.write(buffer) == 0) {
                                    break;
                                }
                            }
                            client.close();
                        }
                    } catch (IOException exception) {
                        key.cancel();
                        try {
                            key.channel().close();
                        } catch (IOException cex) {
                            cex.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    

    可以看到,阻塞和非阻塞的代码是截然不同的。如果为了实现非阻塞而完全重写程序,无疑十分困难


    基于 Netty 的传输

    使用 Netty 的阻塞网络处理如下:

    public class NettyOioServer {
    
        public void server(int port) throws Exception {
            final ByteBuf buf = Unpooled.unreleasableBuffer(
                    Unpooled.copiedBuffer("Hi\n\r", StandardCharsets.UTF_8));
            EventLoopGroup group = new OioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(group)
                        // 使用阻塞模式
                        .channel(OioServerSocketChannel.class)
                        .localAddress(new InetSocketAddress(port))
                        .childHandler(new ChannelInitializer<SocketChannel>() {
    
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(
                                        new SimpleChannelInboundHandler<>() {
                                            @Override
                                            protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
                                                ctx.writeAndFlush(buf.duplicate())
                                                        .addListener(ChannelFutureListener.CLOSE);
                                            }
                                        });
                            }
                        });
                ChannelFuture f = b.bind().sync();
                f.channel().closeFuture().sync();
            } finally {
                group.shutdownGracefully().sync();
            }
        }
    }
    

    而非阻塞版本和阻塞版本几乎一模一样,只需要改动两处地方

    EventLoopGroup group = new NioEventLoopGroup();
    b.group(group).channel(NioServerSocketChannel.class);
    

    传输 API

    传输 API 的核心是 interface Channel,它被用于所有的 IO 操作。每个 Channel 都将被分配一个 ChannelPipeline 和 ChannelConfig,ChannelConfig 包含了该 Channel 的所有配置设置,ChannelPipeline 持有所有将应用于入站和出站数据以及事件的 ChannelHandler 实例

    除了访问所分配的 ChannelPipeline 和 ChannelConfig 之外,也可以利用 Channel 的其他方法

    方法名描述
    eventLoop返回分配给 Channel 的 EventLoop
    pipeline返回分配给 Channel 的 ChannelPipeline
    isActive如果 Channel 活动的,返回 true
    localAddress返回本地的 SocketAddress
    remoteAddress返回远程的 SocketAddress
    write将数据写到远程节点
    flush将之前已写的数据冲刷到底层传输
    writeAndFlush等同于调用 write() 并接着调用 flush()

    内置的传输

    Netty 内置了一些可开箱即用的传输,但它们所支持的协议不尽相同,因此你必须选择一个和你的应用程序所使用协议相容的传输

    名称描述
    NIOio.netty.channel.socket.nio使用 java.nio.channels 包作为基础
    Epollio.netty.channel.epoll由 JNI 驱动的 epoll() 和非阻塞 IO,可支持只有在 Linux 上可用的多种特性,比 NIO 传输更快,且完全非阻塞
    OIOio.netty.channel.socket.oio使用 java.net 包作为基础
    Localio.netty.channel.local可以在 VM 内部通过管道进行通信的本地传输
    Embeddedio.netty.channel.embeddedEmbedded 传输,允许使用 ChannelHandler 而不需要一个真正的基于网络的传输,主要用于测试

    展开全文
  • Netty数据传输

    千次阅读 2016-06-12 10:55:40
    开发网络程序传输数据的过程和方式是被抽象了的,我们不需要关注底层接口,只需要使用 Java API 或其他网络框架Netty 就能达到传输数据的目的。发送数据和接收数据都是字节码。Nothingmore,nothing less。 ...
  • 一、Netty框架介绍 什么是netty?先看下百度百科的解释: Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。...
  • Netty框架

    2019-10-01 19:40:54
    学习Netty框架,三连问:  什么是Netty框架?  为什么要用Netty框架?  怎么用Netty框架? 什么是Netty框架?  Netty是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高...
  • Netty框架简介

    2019-11-05 21:03:37
    Netty框架介绍 早已听说Netty牛逼了,最近有时间学习学习,官网地址:https://netty.io/,Java系的多种服务器/大数据框架,都离不开Netty做出的贡献,例如dubbo,elasticsearch等等,采用的Netty框架做的一些adop....
  • 二.Netty框架简介 1.什么是Netty Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络...
  • netty框架

    2021-03-31 13:55:21
    Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架Netty 是一个广泛使用的 Java 网络编程框架。它活跃和成长于用户社区,像大型公司 Facebook 和 ...
  • 上篇文章高性能NIO框架Netty入门篇我们对Netty做了一个简单的介绍,并且写了一个入门的Demo,客户端往服务端发送一个字符串的消息,服务端回复一个字符串的消息,今天我们来学习下在Netty中怎么使用对象来传输数据。...
  • netty开发tcp数据传输编解码框架使用

    千次阅读 2017-03-07 12:56:03
    尽管站在微内核的角度看,编解码框架并不是Netty微内核的组成部分,但是通过ChannelHandler定制扩展出的编解码框架却是不可或缺的。 下面我们从几个角度详细谈下这个话题,首先一起看下Netty的逻辑架构图:
  • 虽然我们可以使用java进行对象序列化,netty传输,但是java序列化的硬伤太多,比如java序列化没法跨语言、序列化后码流太大、序列化性能太低等等。主流的编解码框架:JBoss的Marshalling包Google的Protobuf基于...
  • Netty框架介绍

    2018-09-07 17:13:34
    Netty框架介绍   一、netty(通讯框架)介紹 1、什么是netty  Netty是一个基于Java NIO类库的异步通讯框架,他的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠和高定制行。 2、netty应用场景  rpc...
  • Netty 是 开源的基于java的网络通信框架,在上篇文章高性能NIO框架Netty-对象传输中对象的传输用的是自定义的编解码器,基于JDK的序列化来实现的,其实Netty自带的Object编解码器就可以实现对象的传输,并且也是基于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,126
精华内容 7,650
关键字:

netty框架数据传输格式