资讯专栏INFORMATION COLUMN

【自己读源码】Netty4.X系列(二) 启动类成员Channel

waterc / 986人阅读

摘要:下面无耻的贴点源码。启动类我们也学,把启动类抽象成两层,方便以后写客户端。别着急,我们慢慢来,下一篇我们会了解以及他的成员,然后,完善我们的程序,增加其接收数据的能力。文章的源码我会同步更新到我的上,欢迎大家,哈哈。

废话两句

这次更新拖了很长时间,第一是自己生病了,第二是因为最开始这篇想写的很大,然后构思了很久,发现不太合适把很多东西写在一起,所以做了点拆分,准备国庆前完成这篇博客。

目的&&期望

开门见山,先说下这篇文章能学到什么

netty中channel的实现类的实现方式和作用

自己动手写netty框架的channel部分和bind方法,完成服务端的端口绑定

Bootstrap主要成员

上一篇我们看了Bootstrap类的大致的组成,也了解了它的一些配置方法,其实都是在设置它的成员变量,有些是ServerBootstrap的也有是它的父类AbstractBootstrap的,在这里,我觉得主要有下面几个。

EventLoopGroup

Channel

Handler

当然,这些只是它的一些接口,具体有多种实现,除了Nio,它也有Bio等其他版本的,继承链也很复杂,这里我们先看下channel的实现。

NioServerSocketChannel 继承链

说到channel,它是Java Nio中的一个重要的成员,不过在netty中,channel是自己封装的一个更抽象的东西,在Nio版本的实现中,它也维护了Java Nio的channel,不过这些都是后话了,我们先看一下它的继承链,这里我自己画了一个简单的。

这里可以看到,它的继承有两个分支,准确的说一条线是继承抽象类,一条线是实现接口,这么做,可以说是netty设计上的考虑,一方面,它是nio的channel,但是同时它又是server端的channel,所以netty选择了这样做来实现。

与Nio的摩擦

看到这里你可能会疑问,这个channel是netty自己封装的,那他是怎么和Nio的channel发生碰撞的呢?
首先,它在构造方法里利用Java Nio的selectProvider 打开了一个socketChannel,然后把这个Nio的Channel和它的准备状态传给父类构造器,然后父类构造器里存储到成员变量中。下面无耻的贴点源码。

    public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }
    //这个DEFAULT_SELECTOR_PROVIDER其实就是select的provide
    private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
    //然后是newSocket打开了一个Channel
    private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
    }
    //最后是调用父类的构造
     public NioServerSocketChannel(ServerSocketChannel channel) {
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }

看到这些,我想大家对Channel有所了解了吧,现在我们来开始实现自己的版本

自己动手 热身

在这之前先说下bootstrap的bind方法,这边netty实现的比较复杂,它是通过各种线程异步,还有它的一个内部类unsafe,最后调用到NioServerSocketChannel的doBind方法,doBind在调用Java Nio的bind方法。这里我们先实现简单版本,它的关于线程的一些设计,我们说到eventloop之后再说。

先来实现Channel和Channel工厂类,方便我们动态new出不同的Channel。

public interface Channel {
    void bind(InetSocketAddress inetSocketAddress);
}

public interface ChannelFactory{

    T newChannel();
}

public class  ReflectChannelFactory implements ChannelFactory {

    private final Class clazz;

    public ReflectChannelFactory(Class clazz) {
        this.clazz = clazz;
    }

    public T newChannel() {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException("can not init");
        }
    }

}
启动类

我们也学netty,把启动类抽象成两层,方便以后写客户端。

public abstract class AbstractBootstrap,C extends Channel> {

    private ChannelFactory channelFactory;

    public B channel(Class clazz){
        this.channelFactory = new ReflectChannelFactory(clazz);
        return (B)this;
    }

    public B bind(Integer port){
        validate();
        doBind(port);
        return (B)this;
    }

    private  void doBind(Integer port){
        Channel channel = channelFactory.newChannel();
        channel.bind(new InetSocketAddress(port));
    }

    public void validate(){
        if(channelFactory == null){
            throw new IllegalArgumentException("channelFactory should be initialized");
        }
    }
}
//服务端暂时没有用到额外的方法,先直接继承就OK了
public class ServerBootstrap extends AbstractBootstrap{


}
Channel实现类

最后我们实现我们的NioChannel,相比netty,我们目前只做了两层抽象。

public abstract class AbstractNioChannel  implements Channel{
    private final SelectableChannel ch;


    public AbstractNioChannel(SelectableChannel ch) {
        this.ch = ch;
    }

    protected SelectableChannel ch() {
        return ch;
    }

    protected abstract void doBind(SocketAddress localAddress) throws Exception;

    public void bind(InetSocketAddress inetSocketAddress) {
        try {
            doBind(inetSocketAddress);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class NioServerSocketChannel extends AbstractNioChannel {

    public NioServerSocketChannel() {

       super(newSocket());
    }

    private static ServerSocketChannel newSocket(){
        try {
            return SelectorProvider.provider().openServerSocketChannel();
        } catch (IOException e) {
            throw new IllegalArgumentException("can not open socket");
        }
    }

    @Override
    protected ServerSocketChannel ch(){
        return (ServerSocketChannel) super.ch();
    }

    @Override
    protected  void doBind(SocketAddress localAddress) throws Exception{
        ch().socket().bind(localAddress);
    }
}
测试

最后写个测试类,来测试下

public class Test {
    public static void main(String[] args) {
        ServerBootstrap sb = new ServerBootstrap();
        sb.channel(NioServerSocketChannel.class).bind(9999);

    }
}
最后

当然,这个连残缺版netty都算不上,在绑定完端口后就自动结束了。别着急,我们慢慢来,下一篇我们会了解EventLoopGroup以及他的成员EventLoop,然后,完善我们的程序,增加其接收数据的能力。
文章的源码我会同步更新到我的gayHub上,欢迎大家star,哈哈。

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

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

相关文章

  • 自己源码Netty4.X系列(一) 启动概览

    摘要:一些想法这个系列想开很久了,自己使用也有一段时间了,利用也编写了一个简单的框架,并运用到工作中了,感觉还不错,趁着这段时间工作不是很忙,来分析一波源码,提升下技术硬实力。 一些想法 这个系列想开很久了,自己使用netty也有一段时间了,利用netty也编写了一个简单的框架,并运用到工作中了,感觉还不错,趁着这段时间工作不是很忙,来分析一波源码,提升下技术硬实力。 结构 这里先看下net...

    qingshanli1988 评论0 收藏0
  • 自己源码Netty4.X系列(三) Channel Register

    摘要:我想这很好的解释了中,仅仅一个都这么复杂,在单线程或者说串行的程序中,编程往往是很简单的,说白了就是调用,调用,调用然后返回。 Netty源码分析(三) 前提概要 这次停更很久了,原因是中途迷茫了一段时间,不过最近调整过来了。不过有点要说下,前几天和业内某个大佬聊天,收获很多,所以这篇博文和之前也会不太一样,我们会先从如果是我自己去实现这个功能需要怎么做开始,然后去看netty源码,与...

    darkbug 评论0 收藏0
  • Netty4.x 源码实战系列):服务端bind流程详解

    摘要:对于,目前大家只知道是个线程组,其内部到底如何实现的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,这里不作详细介绍,后面会有文章作专门详解。 在上一篇《ServerBootstrap 与 Bootstrap 初探》中,我们已经初步的了解了ServerBootstrap是netty进行服务端开发的引导类。 且在上一篇的服务端示例中,我们也看到了,在使用netty进行网络编程时,我...

    laoLiueizo 评论0 收藏0
  • Netty4.x 源码实战系列(一):ServerBootstrap 与 Bootstrap 初探

    摘要:而用于主线程池的属性都定义在中本篇只是简单介绍了一下引导类的配置属性,下一篇我将详细介绍服务端引导类的过程分析。 从Java1.4开始, Java引入了non-blocking IO,简称NIO。NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念。传统的socket是基于stream的,它是单向的,有InputStream表示read和Outpu...

    BakerJ 评论0 收藏0
  • Netty4.x 源码实战系列(三):NioServerSocketChannel全剖析

    摘要:本篇将通过实例化过程,来深入剖析。及初始化完成后,它们会相互连接。我们在回到的构造方法父类构造方法调用完成后,还要初始化一下自己的配置对象是的内部类而又是继承自,通过代码分析,此对象就是就会对底层一些配置设置行为的封装。 根据上一篇《Netty4.x 源码实战系列(二):服务端bind流程详解》所述,在进行服务端开发时,必须通过ServerBootstrap引导类的channel方法来...

    Flink_China 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<