国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Netty4.x 源碼實(shí)戰(zhàn)系列(一):ServerBootstrap 與 Bootstrap 初探

BakerJ / 2085人閱讀

摘要:而用于主線程池的屬性都定義在中本篇只是簡(jiǎn)單介紹了一下引導(dǎo)類的配置屬性,下一篇我將詳細(xì)介紹服務(wù)端引導(dǎo)類的過(guò)程分析。

從Java1.4開(kāi)始, Java引入了non-blocking IO,簡(jiǎn)稱NIO。NIO與傳統(tǒng)socket最大的不同就是引入了Channel和多路復(fù)用selector的概念。傳統(tǒng)的socket是基于stream的,它是單向的,有InputStream表示read和OutputStream表示寫。而Channel是雙工的,既支持讀也支持寫,channel的讀/寫都是面向Buffer。 NIO中引入的多路復(fù)用Selector機(jī)制(如果是linux系統(tǒng),則應(yīng)用的epoll事件通知機(jī)制)可使一個(gè)線程同時(shí)監(jiān)聽(tīng)多個(gè)Channel上發(fā)生的事件。 雖然Java NIO相比于以往確實(shí)是一個(gè)大的突破,但是如果要真正上手進(jìn)行開(kāi)發(fā),且想要開(kāi)發(fā)出好的一個(gè)服務(wù)端網(wǎng)絡(luò)程序,那么你得要花費(fèi)一點(diǎn)功夫了,畢竟Java NIO只是提供了一大堆的API而已,對(duì)于一般的軟件開(kāi)發(fā)人員來(lái)說(shuō)只能呵呵了。因此,社區(qū)中就涌現(xiàn)了很多基于Java NIO的網(wǎng)絡(luò)應(yīng)用框架,其中以Apache的Mina,以及Netty最為出名,從本篇開(kāi)始我們將深入的分析一下Netty的內(nèi)部實(shí)現(xiàn)細(xì)節(jié) 。

</>復(fù)制代碼

  1. 本系列是基于Netty4.1.18這個(gè)版本。

在分析源碼之前,我們還是先看看Netty官方的樣例代碼,了解一下Netty一般是如何進(jìn)行服務(wù)端及客戶端開(kāi)發(fā)的。

Netty服務(wù)端示例:

</>復(fù)制代碼

  1. EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
  2. EventLoopGroup workerGroup = new NioEventLoopGroup();
  3. try {
  4. ServerBootstrap b = new ServerBootstrap(); // (2)
  5. b.group(bossGroup, workerGroup)  // (3)
  6. .channel(NioServerSocketChannel.class) // (4)
  7. .handler(new LoggingHandler()) // (5)
  8. .childHandler(new ChannelInitializer() { // (6)
  9. @Override
  10. public void initChannel(SocketChannel ch) throws Exception {
  11. ch.pipeline().addLast(new DiscardServerHandler());
  12. }
  13. })
  14. .option(ChannelOption.SO_BACKLOG, 128) // (7)
  15. .childOption(ChannelOption.SO_KEEPALIVE, true); // (8)
  16. // Bind and start to accept incoming connections.
  17. ChannelFuture f = b.bind(port).sync(); // (9)
  18. // Wait until the server socket is closed.
  19. // In this example, this does not happen, but you can do that to gracefully
  20. // shut down your server.
  21. f.channel().closeFuture().sync();
  22. } finally {
  23. workerGroup.shutdownGracefully();
  24. bossGroup.shutdownGracefully();
  25. }

上面這段代碼展示了服務(wù)端的一個(gè)基本步驟:

1、 初始化用于Acceptor的主"線程池"以及用于I/O工作的從"線程池";
2、 初始化ServerBootstrap實(shí)例, 此實(shí)例是netty服務(wù)端應(yīng)用開(kāi)發(fā)的入口,也是本篇介紹的重點(diǎn), 下面我們會(huì)深入分析;
3、 通過(guò)ServerBootstrap的group方法,設(shè)置(1)中初始化的主從"線程池";
4、 指定通道channel的類型,由于是服務(wù)端,故而是NioServerSocketChannel;
5、 設(shè)置ServerSocketChannel的處理器(此處不詳述,后面的系列會(huì)進(jìn)行深入分析)
6、 設(shè)置子通道也就是SocketChannel的處理器, 其內(nèi)部是實(shí)際業(yè)務(wù)開(kāi)發(fā)的"主戰(zhàn)場(chǎng)"(此處不詳述,后面的系列會(huì)進(jìn)行深入分析)
7、 配置ServerSocketChannel的選項(xiàng)
8、 配置子通道也就是SocketChannel的選項(xiàng)
9、 綁定并偵聽(tīng)某個(gè)端口

接著,我們?cè)倏纯纯蛻舳耸侨绾伍_(kāi)發(fā)的:

Netty客戶端示例:

</>復(fù)制代碼

  1. public class TimeClient {
  2. public static void main(String[] args) throws Exception {
  3. String host = args[0];
  4. int port = Integer.parseInt(args[1]);
  5. EventLoopGroup workerGroup = new NioEventLoopGroup(); // (1)
  6. try {
  7. Bootstrap b = new Bootstrap(); // (2)
  8. b.group(workerGroup); // (3)
  9. b.channel(NioSocketChannel.class); // (4)
  10. b.option(ChannelOption.SO_KEEPALIVE, true); // (5)
  11. b.handler(new ChannelInitializer() { // (6)
  12. @Override
  13. public void initChannel(SocketChannel ch) throws Exception {
  14. ch.pipeline().addLast(new TimeClientHandler());
  15. }
  16. });
  17. // Start the client.
  18. ChannelFuture f = b.connect(host, port).sync(); // (7)
  19. // Wait until the connection is closed.
  20. f.channel().closeFuture().sync();
  21. } finally {
  22. workerGroup.shutdownGracefully();
  23. }
  24. }
  25. }

客戶端的開(kāi)發(fā)步驟和服務(wù)端都差不多:

1、 初始化用于連接及I/O工作的"線程池";
2、 初始化Bootstrap實(shí)例, 此實(shí)例是netty客戶端應(yīng)用開(kāi)發(fā)的入口,也是本篇介紹的重點(diǎn), 下面我們會(huì)深入分析;
3、 通過(guò)Bootstrap的group方法,設(shè)置(1)中初始化的"線程池";
4、 指定通道channel的類型,由于是客戶端,故而是NioSocketChannel;
5、 設(shè)置SocketChannel的選項(xiàng)(此處不詳述,后面的系列會(huì)進(jìn)行深入分析);
6、 設(shè)置SocketChannel的處理器, 其內(nèi)部是實(shí)際業(yè)務(wù)開(kāi)發(fā)的"主戰(zhàn)場(chǎng)"(此處不詳述,后面的系列會(huì)進(jìn)行深入分析);
7、 連接指定的服務(wù)地址;

通過(guò)對(duì)上面服務(wù)端及客戶端代碼分析,Bootstrap是Netty應(yīng)用開(kāi)發(fā)的入口,如果想要理解Netty內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),那么有必要先了解一下Bootstrap內(nèi)部的實(shí)現(xiàn)機(jī)制。

首先我們先看一下ServerBootstrap及Bootstrap的類繼承結(jié)構(gòu)圖:

通過(guò)類圖我們知道AbstractBootstrap類是ServerBootstrap及Bootstrap的基類,我們先看一下AbstractBootstrap類的主要代碼:

</>復(fù)制代碼

  1. public abstract class AbstractBootstrap, C extends Channel> implements Cloneable {
  2. volatile EventLoopGroup group;
  3. private volatile ChannelFactory channelFactory;
  4. private final Map, Object> options = new LinkedHashMap, Object>();
  5. private final Map, Object> attrs = new LinkedHashMap, Object>();
  6. private volatile ChannelHandler handler;
  7. public B group(EventLoopGroup group) {
  8. if (group == null) {
  9. throw new NullPointerException("group");
  10. }
  11. if (this.group != null) {
  12. throw new IllegalStateException("group set already");
  13. }
  14. this.group = group;
  15. return self();
  16. }
  17. private B self() {
  18. return (B) this;
  19. }
  20. public B channel(Class channelClass) {
  21. if (channelClass == null) {
  22. throw new NullPointerException("channelClass");
  23. }
  24. return channelFactory(new ReflectiveChannelFactory(channelClass));
  25. }
  26. @Deprecated
  27. public B channelFactory(ChannelFactory channelFactory) {
  28. if (channelFactory == null) {
  29. throw new NullPointerException("channelFactory");
  30. }
  31. if (this.channelFactory != null) {
  32. throw new IllegalStateException("channelFactory set already");
  33. }
  34. this.channelFactory = channelFactory;
  35. return self();
  36. }
  37. public B channelFactory(io.netty.channel.ChannelFactory channelFactory) {
  38. return channelFactory((ChannelFactory) channelFactory);
  39. }
  40. public B option(ChannelOption option, T value) {
  41. if (option == null) {
  42. throw new NullPointerException("option");
  43. }
  44. if (value == null) {
  45. synchronized (options) {
  46. options.remove(option);
  47. }
  48. } else {
  49. synchronized (options) {
  50. options.put(option, value);
  51. }
  52. }
  53. return self();
  54. }
  55. public B attr(AttributeKey key, T value) {
  56. if (key == null) {
  57. throw new NullPointerException("key");
  58. }
  59. if (value == null) {
  60. synchronized (attrs) {
  61. attrs.remove(key);
  62. }
  63. } else {
  64. synchronized (attrs) {
  65. attrs.put(key, value);
  66. }
  67. }
  68. return self();
  69. }
  70. public B validate() {
  71. if (group == null) {
  72. throw new IllegalStateException("group not set");
  73. }
  74. if (channelFactory == null) {
  75. throw new IllegalStateException("channel or channelFactory not set");
  76. }
  77. return self();
  78. }
  79. public ChannelFuture bind(int inetPort) {
  80. return bind(new InetSocketAddress(inetPort));
  81. }
  82. public ChannelFuture bind(SocketAddress localAddress) {
  83. validate();
  84. if (localAddress == null) {
  85. throw new NullPointerException("localAddress");
  86. }
  87. return doBind(localAddress);
  88. }
  89. private ChannelFuture doBind(final SocketAddress localAddress) {
  90. final ChannelFuture regFuture = initAndRegister();
  91. final Channel channel = regFuture.channel();
  92. if (regFuture.cause() != null) {
  93. return regFuture;
  94. }
  95. if (regFuture.isDone()) {
  96. // At this point we know that the registration was complete and successful.
  97. ChannelPromise promise = channel.newPromise();
  98. doBind0(regFuture, channel, localAddress, promise);
  99. return promise;
  100. } else {
  101. // Registration future is almost always fulfilled already, but just in case it"s not.
  102. final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
  103. regFuture.addListener(new ChannelFutureListener() {
  104. @Override
  105. public void operationComplete(ChannelFuture future) throws Exception {
  106. Throwable cause = future.cause();
  107. if (cause != null) {
  108. // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
  109. // IllegalStateException once we try to access the EventLoop of the Channel.
  110. promise.setFailure(cause);
  111. } else {
  112. // Registration was successful, so set the correct executor to use.
  113. // See https://github.com/netty/netty/issues/2586
  114. promise.registered();
  115. doBind0(regFuture, channel, localAddress, promise);
  116. }
  117. }
  118. });
  119. return promise;
  120. }
  121. }
  122. final ChannelFuture initAndRegister() {
  123. Channel channel = null;
  124. try {
  125. channel = channelFactory.newChannel();
  126. init(channel);
  127. } catch (Throwable t) {
  128. if (channel != null) {
  129. // channel can be null if newChannel crashed (eg SocketException("too many open files"))
  130. channel.unsafe().closeForcibly();
  131. }
  132. // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
  133. return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
  134. }
  135. ChannelFuture regFuture = config().group().register(channel);
  136. if (regFuture.cause() != null) {
  137. if (channel.isRegistered()) {
  138. channel.close();
  139. } else {
  140. channel.unsafe().closeForcibly();
  141. }
  142. }
  143. return regFuture;
  144. }
  145. abstract void init(Channel channel) throws Exception;
  146. private static void doBind0(
  147. final ChannelFuture regFuture, final Channel channel,
  148. final SocketAddress localAddress, final ChannelPromise promise) {
  149. // This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
  150. // the pipeline in its channelRegistered() implementation.
  151. channel.eventLoop().execute(new Runnable() {
  152. @Override
  153. public void run() {
  154. if (regFuture.isSuccess()) {
  155. channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
  156. } else {
  157. promise.setFailure(regFuture.cause());
  158. }
  159. }
  160. });
  161. }
  162. public B handler(ChannelHandler handler) {
  163. if (handler == null) {
  164. throw new NullPointerException("handler");
  165. }
  166. this.handler = handler;
  167. return self();
  168. }public abstract AbstractBootstrapConfig config();
  169. }

現(xiàn)在我們以示例代碼為出發(fā)點(diǎn),來(lái)詳細(xì)分析一下引導(dǎo)類內(nèi)部實(shí)現(xiàn)細(xì)節(jié):

1、 首先看看服務(wù)端的b.group(bossGroup, workerGroup):

調(diào)用ServerBootstrap的group方法,設(shè)置react模式的主線程池 以及 IO 操作線程池,ServerBootstrap中的group代碼如下:

</>復(fù)制代碼

  1. public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
  2. super.group(parentGroup);
  3. if (childGroup == null) {
  4. throw new NullPointerException("childGroup");
  5. }
  6. if (this.childGroup != null) {
  7. throw new IllegalStateException("childGroup set already");
  8. }
  9. this.childGroup = childGroup;
  10. return this;
  11. }

在group方法中,會(huì)繼續(xù)調(diào)用父類的group方法,而通過(guò)類繼承圖我們知道,super.group(parentGroup)其實(shí)調(diào)用的就是AbstractBootstrap的group方法。AbstractBootstrap中g(shù)roup代碼如下:

</>復(fù)制代碼

  1. public B group(EventLoopGroup group) {
  2. if (group == null) {
  3. throw new NullPointerException("group");
  4. }
  5. if (this.group != null) {
  6. throw new IllegalStateException("group set already");
  7. }
  8. this.group = group;
  9. return self();
  10. }

通過(guò)以上分析,我們知道了AbstractBootstrap中定義了主線程池group的引用,而子線程池childGroup的引用是定義在ServerBootstrap中。

當(dāng)我們查看客戶端Bootstrap的group方法時(shí),我們發(fā)現(xiàn),其是直接調(diào)用的父類AbstractBoostrap的group方法。

2、示例代碼中的 channel()方法

無(wú)論是服務(wù)端還是客戶端,channel調(diào)用的都是基類的channel方法,其實(shí)現(xiàn)細(xì)節(jié)如下:

</>復(fù)制代碼

  1. public B channel(Class channelClass) {
  2. if (channelClass == null) {
  3. throw new NullPointerException("channelClass");
  4. }
  5. return channelFactory(new ReflectiveChannelFactory(channelClass));
  6. }

</>復(fù)制代碼

  1. public B channelFactory(ChannelFactory channelFactory) {
  2. if (channelFactory == null) {
  3. throw new NullPointerException("channelFactory");
  4. }
  5. if (this.channelFactory != null) {
  6. throw new IllegalStateException("channelFactory set already");
  7. }
  8. this.channelFactory = channelFactory;
  9. return self();
  10. }

我們發(fā)現(xiàn),其實(shí)channel方法內(nèi)部,只是初始化了一個(gè)用于生產(chǎn)指定channel類型的工廠實(shí)例。

3、option / handler / attr 方法

option: 設(shè)置通道的選項(xiàng)參數(shù), 對(duì)于服務(wù)端而言就是ServerSocketChannel, 客戶端而言就是SocketChannel;

  handler: 設(shè)置主通道的處理器, 對(duì)于服務(wù)端而言就是ServerSocketChannel,也就是用來(lái)處理Acceptor的操作;

      對(duì)于客戶端的SocketChannel,主要是用來(lái)處理 業(yè)務(wù)操作;

attr: 設(shè)置通道的屬性;

 option / handler / attr方法都定義在AbstractBootstrap中, 所以服務(wù)端和客戶端的引導(dǎo)類方法調(diào)用都是調(diào)用的父類的對(duì)應(yīng)方法。

4、childHandler / childOption / childAttr 方法(只有服務(wù)端ServerBootstrap才有child類型的方法)

  對(duì)于服務(wù)端而言,有兩種通道需要處理, 一種是ServerSocketChannel:用于處理用戶連接的accept操作, 另一種是SocketChannel,表示對(duì)應(yīng)客戶端連接。而對(duì)于客戶端,一般都只有一種channel,也就是SocketChannel。

  因此以child開(kāi)頭的方法,都定義在ServerBootstrap中,表示處理或配置服務(wù)端接收到的對(duì)應(yīng)客戶端連接的SocketChannel通道。

  childHandler / childOption / childAttr 在ServerBootstrap中的對(duì)應(yīng)代碼如下:

</>復(fù)制代碼

  1. public ServerBootstrap childHandler(ChannelHandler childHandler) {
  2. if (childHandler == null) {
  3. throw new NullPointerException("childHandler");
  4. }
  5. this.childHandler = childHandler;
  6. return this;
  7. }

</>復(fù)制代碼

  1. public ServerBootstrap childOption(ChannelOption childOption, T value) {
  2. if (childOption == null) {
  3. throw new NullPointerException("childOption");
  4. }
  5. if (value == null) {
  6. synchronized (childOptions) {
  7. childOptions.remove(childOption);
  8. }
  9. } else {
  10. synchronized (childOptions) {
  11. childOptions.put(childOption, value);
  12. }
  13. }
  14. return this;
  15. }

</>復(fù)制代碼

  1. public ServerBootstrap childAttr(AttributeKey childKey, T value) {
  2. if (childKey == null) {
  3. throw new NullPointerException("childKey");
  4. }
  5. if (value == null) {
  6. childAttrs.remove(childKey);
  7. } else {
  8. childAttrs.put(childKey, value);
  9. }
  10. return this;
  11. }

至此,引導(dǎo)類的屬性配置都設(shè)置完畢了。

本篇總結(jié):

1、服務(wù)端由兩種線程池,用于Acceptor的React主線程和用于I/O操作的React從線程池; 客戶端只有用于連接及IO操作的React的主線程池;

2、ServerBootstrap中定義了服務(wù)端React的"從線程池"對(duì)應(yīng)的相關(guān)配置,都是以child開(kāi)頭的屬性。 而用于"主線程池"channel的屬性都定義在AbstractBootstrap中;

本篇只是簡(jiǎn)單介紹了一下引導(dǎo)類的配置屬性, 下一篇我將詳細(xì)介紹服務(wù)端引導(dǎo)類的Bind過(guò)程分析。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/68110.html

相關(guān)文章

  • Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解

    摘要:對(duì)于,目前大家只知道是個(gè)線程組,其內(nèi)部到底如何實(shí)現(xiàn)的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,這里不作詳細(xì)介紹,后面會(huì)有文章作專門詳解。 在上一篇《ServerBootstrap 與 Bootstrap 初探》中,我們已經(jīng)初步的了解了ServerBootstrap是netty進(jìn)行服務(wù)端開(kāi)發(fā)的引導(dǎo)類。 且在上一篇的服務(wù)端示例中,我們也看到了,在使用netty進(jìn)行網(wǎng)絡(luò)編程時(shí),我...

    laoLiueizo 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(五):深入淺出學(xué)NioEventLoopGroup

    摘要:接下來(lái)的兩篇文章,我將從源碼角度為大家深入淺出的剖析的線程模型工作機(jī)制。我們看一下的源碼通過(guò)的代碼發(fā)現(xiàn),實(shí)現(xiàn)了接口,其內(nèi)部會(huì)通過(guò)指定的默認(rèn)線程工廠來(lái)創(chuàng)建線程,并執(zhí)行相應(yīng)的任務(wù)。至此,初始化完成了。下一篇我們將詳細(xì)介紹,敬請(qǐng)期待。 我們都知道Netty的線程模型是基于React的線程模型,并且我們都知道Netty是一個(gè)高性能的NIO框架,那么其線程模型必定是它的重要貢獻(xiàn)之一。 在使用ne...

    MSchumi 評(píng)論0 收藏0
  • 【自己讀源碼Netty4.X系列() 啟動(dòng)類概覽

    摘要:一些想法這個(gè)系列想開(kāi)很久了,自己使用也有一段時(shí)間了,利用也編寫了一個(gè)簡(jiǎn)單的框架,并運(yùn)用到工作中了,感覺(jué)還不錯(cuò),趁著這段時(shí)間工作不是很忙,來(lái)分析一波源碼,提升下技術(shù)硬實(shí)力。 一些想法 這個(gè)系列想開(kāi)很久了,自己使用netty也有一段時(shí)間了,利用netty也編寫了一個(gè)簡(jiǎn)單的框架,并運(yùn)用到工作中了,感覺(jué)還不錯(cuò),趁著這段時(shí)間工作不是很忙,來(lái)分析一波源碼,提升下技術(shù)硬實(shí)力。 結(jié)構(gòu) 這里先看下net...

    qingshanli1988 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(三):NioServerSocketChannel全剖析

    摘要:本篇將通過(guò)實(shí)例化過(guò)程,來(lái)深入剖析。及初始化完成后,它們會(huì)相互連接。我們?cè)诨氐降臉?gòu)造方法父類構(gòu)造方法調(diào)用完成后,還要初始化一下自己的配置對(duì)象是的內(nèi)部類而又是繼承自,通過(guò)代碼分析,此對(duì)象就是就會(huì)對(duì)底層一些配置設(shè)置行為的封裝。 根據(jù)上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解》所述,在進(jìn)行服務(wù)端開(kāi)發(fā)時(shí),必須通過(guò)ServerBootstrap引導(dǎo)類的channel方法來(lái)...

    Flink_China 評(píng)論0 收藏0
  • 【自己讀源碼Netty4.X系列(二) 啟動(dòng)類成員Channel

    摘要:下面無(wú)恥的貼點(diǎn)源碼。啟動(dòng)類我們也學(xué),把啟動(dòng)類抽象成兩層,方便以后寫客戶端。別著急,我們慢慢來(lái),下一篇我們會(huì)了解以及他的成員,然后,完善我們的程序,增加其接收數(shù)據(jù)的能力。文章的源碼我會(huì)同步更新到我的上,歡迎大家,哈哈。 廢話兩句 這次更新拖了很長(zhǎng)時(shí)間,第一是自己生病了,第二是因?yàn)樽铋_(kāi)始這篇想寫的很大,然后構(gòu)思了很久,發(fā)現(xiàn)不太合適把很多東西寫在一起,所以做了點(diǎn)拆分,準(zhǔn)備國(guó)慶前完成這篇博客。...

    waterc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

BakerJ

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<