摘要:下面无耻的贴点源码。启动类我们也学,把启动类抽象成两层,方便以后写客户端。别着急,我们慢慢来,下一篇我们会了解以及他的成员,然后,完善我们的程序,增加其接收数据的能力。文章的源码我会同步更新到我的上,欢迎大家,哈哈。
废话两句
这次更新拖了很长时间,第一是自己生病了,第二是因为最开始这篇想写的很大,然后构思了很久,发现不太合适把很多东西写在一起,所以做了点拆分,准备国庆前完成这篇博客。
目的&&期望开门见山,先说下这篇文章能学到什么
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 extends T> 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 ChannelFactoryChannel实现类channelFactory; public B channel(Class extends C> 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 { }
最后我们实现我们的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
摘要:一些想法这个系列想开很久了,自己使用也有一段时间了,利用也编写了一个简单的框架,并运用到工作中了,感觉还不错,趁着这段时间工作不是很忙,来分析一波源码,提升下技术硬实力。 一些想法 这个系列想开很久了,自己使用netty也有一段时间了,利用netty也编写了一个简单的框架,并运用到工作中了,感觉还不错,趁着这段时间工作不是很忙,来分析一波源码,提升下技术硬实力。 结构 这里先看下net...
摘要:我想这很好的解释了中,仅仅一个都这么复杂,在单线程或者说串行的程序中,编程往往是很简单的,说白了就是调用,调用,调用然后返回。 Netty源码分析(三) 前提概要 这次停更很久了,原因是中途迷茫了一段时间,不过最近调整过来了。不过有点要说下,前几天和业内某个大佬聊天,收获很多,所以这篇博文和之前也会不太一样,我们会先从如果是我自己去实现这个功能需要怎么做开始,然后去看netty源码,与...
摘要:对于,目前大家只知道是个线程组,其内部到底如何实现的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,这里不作详细介绍,后面会有文章作专门详解。 在上一篇《ServerBootstrap 与 Bootstrap 初探》中,我们已经初步的了解了ServerBootstrap是netty进行服务端开发的引导类。 且在上一篇的服务端示例中,我们也看到了,在使用netty进行网络编程时,我...
摘要:而用于主线程池的属性都定义在中本篇只是简单介绍了一下引导类的配置属性,下一篇我将详细介绍服务端引导类的过程分析。 从Java1.4开始, Java引入了non-blocking IO,简称NIO。NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念。传统的socket是基于stream的,它是单向的,有InputStream表示read和Outpu...
摘要:本篇将通过实例化过程,来深入剖析。及初始化完成后,它们会相互连接。我们在回到的构造方法父类构造方法调用完成后,还要初始化一下自己的配置对象是的内部类而又是继承自,通过代码分析,此对象就是就会对底层一些配置设置行为的封装。 根据上一篇《Netty4.x 源码实战系列(二):服务端bind流程详解》所述,在进行服务端开发时,必须通过ServerBootstrap引导类的channel方法来...
阅读 2454·2021-09-22 16:05
阅读 2914·2021-09-10 11:24
阅读 3607·2019-08-30 12:47
阅读 2915·2019-08-29 15:42
阅读 3345·2019-08-29 15:32
阅读 1920·2019-08-26 11:48
阅读 1059·2019-08-23 14:40
阅读 880·2019-08-23 14:33