摘要:下面無恥的貼點源碼。啟動類我們也學,把啟動類抽象成兩層,方便以后寫客戶端。別著急,我們慢慢來,下一篇我們會了解以及他的成員,然后,完善我們的程序,增加其接收數據的能力。文章的源碼我會同步更新到我的上,歡迎大家,哈哈。
廢話兩句
這次更新拖了很長時間,第一是自己生病了,第二是因為最開始這篇想寫的很大,然后構思了很久,發現不太合適把很多東西寫在一起,所以做了點拆分,準備國慶前完成這篇博客。
目的&&期望開門見山,先說下這篇文章能學到什么
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,哈哈。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/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方法來...
閱讀 2478·2021-09-22 16:05
閱讀 2961·2021-09-10 11:24
閱讀 3633·2019-08-30 12:47
閱讀 2941·2019-08-29 15:42
閱讀 3379·2019-08-29 15:32
閱讀 1946·2019-08-26 11:48
閱讀 1083·2019-08-23 14:40
閱讀 903·2019-08-23 14:33