nio之netty5应用

简介:   1、netty5和netty4的区别不是很大,但是与netty3差别还是有的。这里不介绍netty4,因为和netty5的方式都差不多。netty5的复杂性相对于netty3要多很多了。基本上架构都被重构了。

  1、netty5和netty4的区别不是很大,但是与netty3差别还是有的。这里不介绍netty4,因为和netty5的方式都差不多。netty5的复杂性相对于netty3要多很多了。基本上架构都被重构了。所以这里主要是介绍一些属性和用法。

  2、核心的变化主要有:

  支持Android
 
  提供了:
  •  移动设备变成更加强大
  • 通过Ice Cream Sandwich解决了在ADK中最著名的与NIO和SSLEngine相关的问题,且
  • 用户显然想要重用他们应用中的的编解码和处理器代码。
  我们决定官方支持Android(4.0及以上版本)
 
  简化处理器层次
 
  ChannelInboundHandler和ChannelOutboundHandler整合为ChannelHandler。ChannelHandler现在包含输入和输出的处理方法。
 
  ChannelInboundHandlerAdapter,ChannelOutboundHandlerAdapter和ChannelDuplexHandlerAdapter已被废弃,由 ChannelHandlerAdapter代替。
 
  由于现在无法区分处理器(handler) 是输入还是输出的处理器,CombinedChannelDuplexHandler现在由 ChannelHandlerAppender代替。
 
  更多相关变化,可参考 https://github.com/netty/netty/pull/1999
 
  channelRead0() → messageReceived()
 
  我知道。这是一个愚蠢的错误。如果你使用了SimpleChannelInboundHandler,你需要把channelRead0()重命名为messageReceived()。
 
  废弃中移除的
 
  Channel.deregister()已被移除。不再生效和被使用。取而代之的,我们将允许Channel被充注册到不同的事件循环。
 
  ChannelHandlerContext.attr(..) == Channel.attr(..)
 
  Channel和ChannelHandlerContext类都实现了AttributeMap接口,使用户可以在其上关联一个或多个属性。有时会让用户感到困惑的是Channel和ChannelHandlerContext都有其自己的存储用户定义属性的容器。例如,即使你通过Channel.attr(KEY_X).set(valueX)给属性'KEY_X’赋值,你却无法通过ChannelHandlerContext.attr(KEY_X).get()方法获取到值。反之亦是如此。这种行为不仅仅令人不解而且还浪费内存。
 
  为了解决这个问题,我们决定每个Channel内部仅保留一个map。AttributeMap总是用AttributeKey作为它的key。AttributeKey确保键的唯一性,因此每个Channel中如果存在一个以上的属性容易是多余的。只要用户把他自己的AttributeKey定义成ChannelHandler的private static final变量,就不会有出现重复key的风险。
 
  更简单更精确的缓冲区泄漏追踪
 
 
  之前,查找缓冲区泄漏是很困难的,并且泄漏的警告信息也不是很有帮助。现在我们有了增强的泄漏报告机制,该机制会在增长超过上限时触发。
 
  更多的信息可查看:http://netty.io/wiki/reference-counted-objects.html 。由于该特性十分重要,所以也移植入了4..0.14.Final版中。
 
  PooledByteBufAllocator成为默认的allocator
 
  在4.x版本中,UnpooledByteBufAllocator是默认的allocator,尽管其存在某些限制。现在PooledByteBufAllocator已经广泛使用一段时间,并且我们有了增强的缓冲区泄漏追踪机制,所以是时候让PooledByteBufAllocator成为默认了。
 
  全局唯一的Channel ID
  每个Channel现在有了全局唯一的ID,其生成的依据是:
 
   * MAC地址(EUI-48或是EUI-64),最好是全局唯一的,
   * 当前进程的ID
   * System#currentTimeMillis()
   * System#nanoTime()
   * 随机的32位整数,以及
   * 系列递增的32位整数
 
  可通过Channel.id()方法获取Channel的ID。
 
  更灵活的线程模型
 
 
  增加了新的ChannelHandlerInvoker接口,用于使用户可以选择使用哪个线程调用事件处理方法。替代之前的在向ChannelPipeline添加 ChannelHandler时指定一个EventExecutor的方式,使用该特性需要指定一个用户自定义的 ChannelHandlerInvoker实现。
 
  关于该变化更多的信息,可参考: https://github.com/netty/netty/commit/132af3a485015ff912bd567a47881814d2ce1828
 
  EmbeddedChannel的易用性
 
  EmbeddedChannel中的readInbound()和readOutbound()方法返回专门类型的参数,因此你不必在转换他们的返回值。这可以简化你的测试用例代码。
EmbeddedChannel ch = ...;

// BEFORE:
FullHttpRequest req = (FullHttpRequest) ch.readInbound();

// AFTER:
FullHttpRequest req = ch.readInbound();

 
  使用Executor代替ThreadFactory
 
  有些应用要求用户使用Executor运行他们的任务。4.x版本要求用户在创建事件循环(event loop)时指定ThreadFacotry,现在不再是这样了。
 
  关于该变化的更多信息,可参考:https://github.com/netty/netty/pull/1762
 
  Class loader友好化
 
  一些类型,如AttributeKey对于在容器环境下运行的应用是不友好的,现在不是了。
 
  编解码和处理器(handlers)
 
   * XmlFrameDecoder支持流式的XML文档
 
   * 二进制的memcache协议编解码
   * 支持SPDY/3.1 (也移植到了4.x版本)
   * 重构了HTTP多部分的编解码
 

  3、这里写了一个简单的实现过程,来区分netty5和netty3的写法

  1)服务类和处理类

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class Server {

    public static void main(String[] args) {
        //服务类
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        //声明两个线程池
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();

        try {
            //设置线程组
            serverBootstrap.group(boss,work);
            //设置服务socket工厂
            serverBootstrap.channel(NioServerSocketChannel.class);
            //设置管道
            serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
                protected void initChannel(Channel channel) throws Exception {
                    channel.pipeline().addLast(new StringDecoder());
                    channel.pipeline().addLast(new StringEncoder());
                    channel.pipeline().addLast(new ServerHandler());
                }
            });
            //设置服务器连接数
            serverBootstrap.option(ChannelOption.SO_BACKLOG,2048);
            //设置tcp延迟状态
            serverBootstrap.option(ChannelOption.TCP_NODELAY,true);
            //设置激活状态,2小时清除
            serverBootstrap.option(ChannelOption.SO_KEEPALIVE,true);
            //监听端口
            ChannelFuture channelFuture = serverBootstrap.bind(9000);
            //等待服务器关闭
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }

    }

}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class ServerHandler extends SimpleChannelInboundHandler<String> {

    //接收消息并处理
    protected void messageReceived(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
        System.out.println(s);
        channelHandlerContext.writeAndFlush("hello client");
    }
}

  2)客户端和处理类

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.net.InetSocketAddress;
import java.util.Scanner;

//单个客户端
public class Client {

    public static void main(String[] args) {

        //服务类
        Bootstrap bootstrap = new Bootstrap();
        //线程池
        EventLoopGroup client = new NioEventLoopGroup();

        try {
            //设置线程组
            bootstrap.group(client);
            //设置socket工厂
            bootstrap.channel(NioSocketChannel.class);
            //设置管道处理
            bootstrap.handler(new ChannelInitializer<Channel>() {
                protected void initChannel(Channel channel) throws Exception {
                    channel.pipeline().addLast(new StringEncoder());
                    channel.pipeline().addLast(new StringDecoder());
                    channel.pipeline().addLast(new ClientHandler());
                }
            });
            //连接服务器
            ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress("localhost", 9000));
            //输入信息测试
            Scanner scanner = new Scanner(System.in);
            while (true) {
                String msg = scanner.nextLine();
                channelFuture.channel().writeAndFlush(msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            client.shutdownGracefully();
        }
    }
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class ClientHandler extends SimpleChannelInboundHandler<String>{

    //接收消息
    protected void messageReceived(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
        System.out.println(s);
    }
}

  3)多个客户端

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicInteger;

//多个客户端连接
public class MClient {

    //服务类
    private Bootstrap bootstrap = new Bootstrap();
    //因为线程组里面是线程安全的,所以这里采用数组的形式
    private List<Channel> channels = new ArrayList<Channel>();
    //原子类,用于计数
    private AtomicInteger atomicInteger = new AtomicInteger();
    //初始化操作
    public void init(int count) {
        //声明线程池
        EventLoopGroup client = new NioEventLoopGroup();
        //设置线程组
        bootstrap.group(client);
        //设置socket工厂
        bootstrap.channel(NioSocketChannel.class);
        //设置管道
        bootstrap.handler(new ChannelInitializer<Channel>() {
            protected void initChannel(Channel channel) throws Exception {
                channel.pipeline().addLast(new StringEncoder());
                channel.pipeline().addLast(new StringDecoder());
                channel.pipeline().addLast(new ClientHandler());
            }
        });
        //初始化连接
        for (int i = 0; i < count; i++) {
            ChannelFuture channelFuture = bootstrap.connect("10.0.20.154", 9000);
            channels.add(channelFuture.channel());
        }
    }

    //获取下一个channel
    public Channel nextChannel() {
        return this.getChannel(0);
    }

    private Channel getChannel(int n) {
        //平均获取其中的channel
        Channel channel = channels.get(Math.abs(atomicInteger.getAndIncrement() % channels.size()));
        //判断是否连接
        if (!channel.isActive()) {
            //如果没有连接,选择激活替换
            channels.set(channels.indexOf(channel), bootstrap.connect("10.0.20.154", 9000).channel());
            //超出总长度,直接抛异常
            if (n>=channels.size()) {
                throw new RuntimeException("no use channel");
            }
            //递归,目的是获取下一个,直到数组没有channel
            return getChannel(n+1);
        }
        return channel;
    }

    public static void main(String[] args) {
        MClient mClient = new MClient();
        mClient.init(5);
        Scanner scanner = new Scanner(System.in);
        while (true) {
            try {
                String msg = scanner.nextLine();
                mClient.nextChannel().writeAndFlush(msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 

相关文章
|
25天前
|
消息中间件 监控 Java
BIO、NIO、AIO在不同场景下的应用对比
BIO(阻塞I/O)、NIO(非阻塞I/O)和AIO(异步I/O)是Java中处理I/O操作的三种模式。BIO适用于连接数少且稳定的场景;NIO通过非阻塞模式提高并发处理能力,适合高并发场景;AIO则完全异步,适合需要高效、低延迟的I/O操作场景。
82 4
|
4月前
|
设计模式
Lettuce的特性和内部实现问题之Netty NIO的性能优于BIO的问题如何解决
Lettuce的特性和内部实现问题之Netty NIO的性能优于BIO的问题如何解决
|
5月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
1月前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
3月前
|
Java
Netty BIO/NIO/AIO介绍
Netty BIO/NIO/AIO介绍
|
4月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
150 0
|
4月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
89 0
|
5月前
|
前端开发 Java 数据处理
使用Netty构建高性能的网络应用
使用Netty构建高性能的网络应用
|
6月前
|
Java 视频直播 数据库连接
Java I/O 模型详解:BIO、NIO 与 AIO 的特性与应用
Java I/O 模型详解:BIO、NIO 与 AIO 的特性与应用
73 2
|
5月前
|
监控 网络协议 Java
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
85 0