您的位置:首页 > 编程语言 > Java开发

学习 java netty (三) -- Channel

2015-07-30 00:04 471 查看

学习 java netty (三) – Channel

前言:netty封装的channel,看一下官网的定义

A nexus to a network socket or a component which is capable of I/O operations such as read, write, connect, and bind.

可以I/O操作(如读,写,连接和绑定)的连网套接字或组件


A channel provides a user:

All I/O operations are asynchronous

netty中channel所有的操作都是异步的,请求将立即返回,但不保证请求完成


Channels are hierarchical

channel是分层的,一个Channel可以有一个父母,取决于它是如何创建的,比如一个SocketChannel(客户端套接字)被ServerSocketChannel(服务端套接字)连接了,那么ServerSocketChannel就类似与SocketChannel的 parent


Downcast to access transport-specific operations

向下转型来访问特定的传输协议,也就是说转为子类型也可以访问父类型的操作


Release resources

释放资源,Channel内部也是Socket文件句柄,我们要close()

Channel是netty抽象出来的接口,不同与Nio中的channel,netty中的Channel封装了网络IO和网络IO相关的操作。功能非常多

源码:

//Channel是一个接口类,继承自AttributeMap和Comparable,AttributeMap是存储属性的一个map,Comparable接口强行对实现它的每个类的对象进行整体排序
public interface Channel extends AttributeMap, Comparable<Channel> {
    //返回唯一标识
    ChannelId id();
    //返回被注册的事件循环
    EventLoop eventLoop();
    //返回parent channel
    Channel parent();
    //返回channel(socket)的配置
    ChannelConfig config();
    //判断是否打开,注册,活跃
    boolean isOpen();
    boolean isRegistered();
    //源数据,可以获得底层的tcp参数设置等
    ChannelMetadata metadata();
    //本地地址和远端地址
    SocketAddress localAddress();
    SocketAddress remoteAddress();
    //关闭Channel,返回ChannelFuture意味着是异步的,不阻塞立即返回,在未来Future我们可以获得执行操作的状态
    ChannelFuture closeFuture();
    //数据是可读的
    boolean isWritable();
    long bytesBeforeWritable();
    Unsafe unsafe();
    ChannelPipeline pipeline();
    ByteBufAllocator alloc();
    ChannelPromise newPromise();
    ChannelProgressivePromise newProgressivePromise();
    ChannelFuture newSucceededFuture();
    ChannelFuture newFailedFuture(Throwable cause);
    ChannelPromise voidPromise();
    ChannelFuture bind(SocketAddress localAddress);
    ChannelFuture connect(SocketAddress remoteAddress);
    ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress);
    ChannelFuture disconnect();
    ChannelFuture close();
    ChannelFuture deregister();
    ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise);
    ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise);
    ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
    ChannelFuture disconnect(ChannelPromise promise);
    ChannelFuture close(ChannelPromise promise);
    ChannelFuture deregister(ChannelPromise promise);
    Channel read();
    ChannelFuture write(Object msg);
    ChannelFuture write(Object msg, ChannelPromise promise);
    Channel flush();
    ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);
    ChannelFuture writeAndFlush(Object msg);
    interface Unsafe


从接口类可以看出Channel操作是非常多的,后面的方法我没有写注释,可以看见都是一些操作,返回ChannelFuture或者ChannelPromise,下面选一些重点来解释。

Channel

封装了许多协议tcp,udp等,通讯模型Nio,oio,Aio等,从上面可以看出对这些操作提供了一个整体的封装接口就是Channel,必要的时候可以进行转型。

接口中提供:

Channel的状态,isOpen(),isWritable()

Channel的配置参数,config()

Channel支持的操作,bind(),read(),connect()

ChannelFuture

所有的Channel操作都是异步的,Channel的返回ChannelFuture的一些操作并不阻塞,而是立即返回,在未来某个时刻我们能够获得状态来判断该操作的状态是完成还是进行还是取消。

注意ChannelFuture对象是操作一执行就立即返回了。ChannelFuture中提供的方法就是让检查操作完成状况。

ChannelPromise

继承关系:

Future <— ChannelFuture <— ChannelPromise

ChannelPromise继承了ChannelFuture,ChannelFuture方法主要是判断操作未来的状态,而ChannelPromise除了继承ChannelFuture的方法外,还实现了设置未来状态的写方法,

源码上写的是

Special {@link ChannelFuture} which is writable.

特殊的可写的ChannelFuture

比如ChannelFuture返回错误等情况,当我们使用ChannelPromise时,就能改变返回结果,唤醒其他操作,有点线程中条件变量的感觉。

ChannelPipeline

说到ChannelPipeline先要说责任链设计模式,简单来讲就是将一些能处理请求的对象串起来形成一条链,被处理的对象不知道被谁处理,所以在这条处理链上轮寻过,该被谁处理谁就接受此对象进行处理。

现实生活的例子,比如上级分派了一个任务做一款软件(被处理对象),放眼望去有一排攻城狮(处理请求对象),于是此任务在他们之间传递,每个攻城狮判断自己是否能做,能做就接受请求。


pipeline就是这条责任链,我们可以往上面注册,增添,删除处理事件对象,然后当待处理对象在此pipeline上传递时,哪个处理事件对象能处理则接收它。


责任链设计模式

部分代码:

public void initChannel(SocketChannel ch) throws Exception {
    ch.pipeline().addLast(new StringDecoder());
    //分隔符解码器
    DelimiterBasedFrameDecoder
    ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
    ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
}


上面添加了3个处理事件对象,字符串解码,分隔符解码,日志信息。当产生对应事件时,它们会接受并处理

注意:每个Channel在实例化的时候都会自动创建一个ChannelPipeline实例。ChannelPipeline是线程安全的,可以在任意时刻增加删除。

ChannelHandler

ChannelHandler就是ChannelPipeline上面注册的处理事件对象,每个ChannelHandler接口的实现类完成一定的功能,并可以灵活的在Pipeline流水线上增加,ChannelHandler也称为事件拦截器,遇到能处理的对象事件就拦截下来处理

ChannelHandler支持注解

@Sharable是多个Pipeline共用一个ChannelHandler

@skip是跳过此ChannelHandler

ChannelHandlerAdapter

ChannelHandlerAdapter给用户提供了ChannelHandler的适配器,我们可以自定义类来继承ChannelHandlerAdapter然后根据自己需要如何处理事件对象来重新实现ChannelHandler的方法。

例子:

public class ServerHandler extends ChannelHandlerAdapter {
    ServerHandler(){
        System.out.println("ServerHandler被创建");
    }
    //重写此方法
    public void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception{
        ctx.write(msg);
        System.out.println("发送msg");
        ByteBuf buf = (ByteBuf)msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("server收到:" + body);
        ctx.write(resp);
 }

    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception{
        //将write数据先写到缓冲区中,等到complete状态再刷新缓冲区
        ctx.flush();
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
        //有错误时打印错误并且关闭ctx
        logger.log(Level.WARNING, "unexcepted exception from downstream", cause);
        ctx.close();
    }
}


到此Channel和Channel关系密切的类和接口差不多就简单介绍完了,我们大致能知道它们的原理和它们的用法后,在看和使用其他继承它们的拓展类就方便多了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: