IO网络编程(五)

Netty核心组件

Channel
ChannelFuture
EventLoop
ChannelHandler
ChannelPipeline

Channel、EventLoop 和 ChannelFuture

Channel、EventLoop 和 ChannelFuture这三个抽象类聚合在一起,可以被认为是 Netty 网络抽象的代表:
 Channel—Socket;
 EventLoop—控制流、多线程处理、并发;
 ChannelFuture—异步通知。

1.Channel接口

基本的 I/O 操作(bind()、connect()、read()和 write())依赖于底层网络传输所提供的原语。在基于 Java 的网络编程中,其基本的构造是 class Socket。Netty 的 Channel 接 口所提供的 API,大大地降低了直接使用 Socket 类的复杂性。channel是一个管道,用于连接字节缓冲区Buf和另一端的实体,这个实例可以是Socket,也可以是File, 在Nio网络编程模型中, 服务端和客户端进行IO数据交互(得到彼此推送的信息)的媒介就是Channel.

    ChannelId id();
	//返回channel所注册的 eventLoop
    EventLoop eventLoop();
	//返回当前Channel的父channel
    Channel parent();
	//关于channel的 一些列配置信息
    ChannelConfig config();
	//检查channel是否开启
    boolean isOpen();
	//检查channel是否注册
    boolean isRegistered();
	//检查channel是否存活
    boolean isActive();
	// 返回channel的元数据
    ChannelMetadata metadata();
	
    //  服务器的ip地址
	SocketAddress localAddress();

	// remoteAddress 客户端的ip地址
    SocketAddress remoteAddress();

    ChannelFuture closeFuture();

    boolean isWritable();

    long bytesBeforeUnwritable();

    long bytesBeforeWritable();
	//内部的一个Unsafe方法
    Channel.Unsafe unsafe();
	// 返回Channel的管道
    ChannelPipeline pipeline();

    ByteBufAllocator alloc();

    Channel read();

    Channel flush();

public interface Unsafe {
        Handle recvBufAllocHandle();

        SocketAddress localAddress();

        SocketAddress remoteAddress();
		//  把channel注册进EventLoop
        void register(EventLoop var1, ChannelPromise var2);
		//给channel绑定一个 adress
        void bind(SocketAddress var1, ChannelPromise var2);
		//......
        void connect(SocketAddress var1, SocketAddress var2, ChannelPromise var3);

        void disconnect(ChannelPromise var1);

        void close(ChannelPromise var1);

        void closeForcibly();

        void deregister(ChannelPromise var1);

        void beginRead();

        void write(Object var1, ChannelPromise var2);

        void flush();

        ChannelPromise voidPromise();

        ChannelOutboundBuffer outboundBuffer();
    }

此外,Channel 也是拥有许多预定义的、专门化实现的广泛类层次结构的根,下面是一个简短的部分清单:
 EmbeddedChannel;
 LocalServerChannel;
 NioDatagramChannel;
 NioSctpChannel;
 NioSocketChannel。

EventLoop 接口

EventLoop 定义了 Netty 的核心抽象,用于处理连接的生命周期中所发生的事件。运行任务处理的在编程上的构造通常称作事件循环,Netty使用EventLoop来描述。一个EventLoop将由一个永远不会变的Thread驱动,它可以被指派给多个channel,任务提交给Eventloop之后可以立即执行或者调度执行。任务的执行顺序是以先进先出的顺序执行。
 一个 EventLoopGroup 包含一个或者多个 EventLoop;
 一个 EventLoop 在它的生命周期内只和一个 Thread 绑定;
 所有由 EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理;
 一个 Channel 在它的生命周期内只注册于一个 EventLoop;
 一个 EventLoop 可能会被分配给一个或多个 Channel。
关系如下图:
在这里插入图片描述

ChannelFuture接口

Netty 为异步非阻塞,即所有的 I/O 操作都为异步的,因此,我们不能立刻得知消息是否已经被处理了。JDK 预置了 interface java.util.concurrent.Future,但是其所提供的实现,只 允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以 Netty 提供了它自己的实现——ChannelFuture,用于在执行异步操作的时候使用。通过该接口的 addListener() 方法注册一个ChannelFutureListener,当操作执行成功或者失败时,监听就会自动触发返回结果。

Channel channel = ...
ChannelFuture future = channel.connect(new InetSocketAddress("192.168.0.1",6666));
// 注册一个监听器
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
// do something....
} else {
// 输出错误信息
Throwable cause = future.cause();
cause.printStackTrace();
// do something....
}
}
});

ChannelFutureListener接口中还提供了几个简单的默认实现

public interface ChannelFutureListener extends GenericFutureListener<ChannelFuture> {
	// 在Future完成时关闭
    ChannelFutureListener CLOSE = new ChannelFutureListener() {
        public void operationComplete(ChannelFuture future) {
            future.channel().close();
        }
    };
    // 如果失败则关闭
    ChannelFutureListener CLOSE_ON_FAILURE = new ChannelFutureListener() {
        public void operationComplete(ChannelFuture future) {
            if (!future.isSuccess()) {
                future.channel().close();
            }

        }
    };
    // 将异常信息传递给下一个ChannelHandler
    ChannelFutureListener FIRE_EXCEPTION_ON_FAILURE = new ChannelFutureListener() {
        public void operationComplete(ChannelFuture future) {
            if (!future.isSuccess()) {
                future.channel().pipeline().fireExceptionCaught(future.cause());
            }

        }
    };
}

ChannelHandler和ChannelPipeline

ChannelHandler

ChannelHandler属于业务的核心接口,用于处理IO事件或者拦截IO操作,并将其转发到ChannelPipeline(业务处理链)中的下一个处理程序。
ChannelHandler的主要用途包括:
对入站与出站数据的业务逻辑处理
记录日志
将数据从一种格式转换为另一种格式,实现编解码器。以一次HTTP协议(或者其他应用层协议)的流程为例,数据在网络传输时的单位为字节,当客户端发送请求到服务器时,服务器需要通过解码器(处理入站消息)将字节解码为协议的消息内容,服务器在发送响应的时候(处理出站消息),还需要通过编码器将消息内容编码为字节。
捕获异常
提供Channel生命周期内的通知,如Channel活动时与非活动时

入站消息与出站消息由其对应的接口ChannelInboundHandlerChannelOutboundHandler负责,这两个接口定义了监听Channel的生命周期的状态改变事件的回调函数。ChannelInboundHandlerAdapter与ChannelOutboundHandlerAdapter都继承于ChannelHandlerAdapter,该抽象类简单实现了ChannelHandler接口。

Pipeline与ChannelPipeline

ChannelPipeline是一个handler的集合,它负责处理和拦截出站和入站的事件和操作。ChannelPipeline实现了拦截过滤器模式,使用户能控制事件的处理方式。在Netty中,每个Channel都有且只有一个ChannelPipeline与之对应。
一个 Channel 包含了一个 ChannelPipeline,而 ChannelPipeline 中又维护了一个由 ChannelHandlerContext 组成的双向链表,并且每个 ChannelHandlerContext 中又关联着一个 ChannelHandler。
在这里插入图片描述

小结

在这里插入图片描述
上图中各个组件关系如下:
1.最重要的就是NioEventLoop,起了两种类型的线程,一个是监听客户端连接,另一个是处理客户端读写
2.channel就是对一条连接的封装,在channel封装的api中可以进行数据读写
3.对数据的读写可以看做是逻辑处理的链(Pipeline),每一个的逻辑处理都是一个ChannelHandler
4.在一条channel中的数据读写都是基于ByteBuffer来操作的。

参考:https://blog.csdn.net/a724888/article/details/80742828
https://www.cnblogs.com/clawhub/p/11968113.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值