netty入门02

本文来源:http://blog.csdn.net/zxhoo/article/details/17419229

感谢博主。本文仅供参考学习。

目录(?)[-]

  1. bootstrap包
  2. Bootstrap继承结构
  3. Bootstrap例子
  4. Builder模式
  5. AbstractBootstrap
  6. 设置各个Part
  7. ChannelFactory
  8. Bootstrapconnect
  9. AbstractBootstrapinitAndRegister
  10. Bootstrapinit方法
  11. 继续BootstrapdoConnect

Netty4的代码比我想象的要复杂的多,不

Netty4的代码比我想象的要复杂的多,不过Netty4很好的将这种复杂性隐藏了起来,暴露出来的,是一个相对容易使用的接口。Bootstrap就是Netty试图隐藏这种复杂性的一个例子。

bootstrap包

bootstrap包是Netty4代码里最简单的一个包,总共只有4个类:

Bootstrap继承结构

AbstractBootstrap是抽象类,有两个具体的实现,Bootstrap和ServerBootstrap:

Bootstrap例子

Netty4自带的例子里有一个EchoClient,看看它是如何使用Bootstrap启动一个客户端程序的:

[java] view plain copy

  1. public class EchoClient {
  2. private final String host;
  3. private final int port;
  4. private final int firstMessageSize;
  5. public EchoClient(String host, int port, int firstMessageSize) {
  6. this.host = host;
  7. this.port = port;
  8. this.firstMessageSize = firstMessageSize;
  9. }
  10. public void run() throws Exception {
  11. // Configure the client.
  12. EventLoopGroup group = new NioEventLoopGroup();
  13. try {
  14. Bootstrap b = new Bootstrap();
  15. b.group(group)
  16. .channel(NioSocketChannel.class)
  17. .option(ChannelOption.TCP_NODELAY, true)
  18. .handler(new ChannelInitializer<SocketChannel>() {
  19. @Override
  20. public void initChannel(SocketChannel ch) throws Exception {
  21. ch.pipeline().addLast(
  22. //new LoggingHandler(LogLevel.INFO),
  23. new EchoClientHandler(firstMessageSize));
  24. }
  25. });
  26. // Start the client.
  27. ChannelFuture f = b.connect(host, port).sync();
  28. // Wait until the connection is closed.
  29. f.channel().closeFuture().sync();
  30. } finally {
  31. // Shut down the event loop to terminate all threads.
  32. group.shutdownGracefully();
  33. }
  34. }
  35. public static void main(String[] args) throws Exception {
  36. // ...
  37. }
  38. }

Builder模式?

看上面的例子,Bootstrap的使用很像Builder模式,Bootstrap就是Builder,EventLoopGroup、Channel和Handler等是各种Part。稍有不同的是,准备好各种Part后,并不是直接build出一个Product来,而是直接通过connect()方法使用这个Product。

AbstractBootstrap

为了弄清楚Bootstrap如何工作,我们先从AbstractBootstrap入手:

[java] view plain copy

  1. public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  2. private volatile EventLoopGroup group;
  3. private volatile ChannelFactory<? extends C> channelFactory;
  4. private volatile SocketAddress localAddress;
  5. private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
  6. private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
  7. private volatile ChannelHandler handler;
  8. // ...
  9. }

可以看到,AbstractBootstrap这个抽象Builder一共需要有6个Part,如下图所示:

设置各个Part

AbstractBootstrap有一组方法用来设置各个Part,例如下面这些:

[java] view plain copy

  1. public B group(EventLoopGroup group)
  2. public B channel(Class<? extends C> channelClass)
  3. public B channelFactory(ChannelFactory<? extends C> channelFactory)
  4. public B localAddress(SocketAddress localAddress)
  5. public <T> B option(ChannelOption<T> option, T value)
  6. public <T> B attr(AttributeKey<T> key, T value)
  7. public B handler(ChannelHandler handler)

还有一组对应方法获得各个Part,如下:

[java] view plain copy

  1. final SocketAddress localAddress()
  2. final ChannelFactory<? extends C> channelFactory()
  3. final ChannelHandler handler()
  4. public final EventLoopGroup group()
  5. final Map<ChannelOption<?>, Object> options()
  6. final Map<AttributeKey<?>, Object> attrs()

ChannelFactory

AbstractBootstrap通过ChannelFactory创建Channel实例,channel(channelClass)方法看起来好像是设置了一个Channel,但实际上只是设置了默认的ChannelFactory实现:

[java] view plain copy

  1. public B channel(Class<? extends C> channelClass) {
  2. if (channelClass == null) {
  3. throw new NullPointerException("channelClass");
  4. }
  5. return channelFactory(new BootstrapChannelFactory<C>(channelClass));
  6. }

默认的ChannelFactory实现使用反射创建Channel实例:

[java] view plain copy

  1. private static final class BootstrapChannelFactory<T extends Channel> implements ChannelFactory<T> {
  2. private final Class<? extends T> clazz;
  3. BootstrapChannelFactory(Class<? extends T> clazz) {
  4. this.clazz = clazz;
  5. }
  6. @Override
  7. public T newChannel() {
  8. try {
  9. return clazz.newInstance();
  10. } catch (Throwable t) {
  11. throw new ChannelException("Unable to create Channel from class " + clazz, t);
  12. }
  13. }
  14. }

Bootstrap.connect()

再来看Bootstrap类的connect()方法:

[java] view plain copy

  1. public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
  2. if (remoteAddress == null) {
  3. throw new NullPointerException("remoteAddress");
  4. }
  5. validate();
  6. return doConnect(remoteAddress, localAddress);
  7. }

connect()方法调用validate()方法看各个Part是否准备就绪,然后调用doConnect()方法:

[java] view plain copy

  1. private ChannelFuture doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
  2. final ChannelFuture regFuture = initAndRegister();
  3. final Channel channel = regFuture.channel();
  4. if (regFuture.cause() != null) {
  5. return regFuture;
  6. }
  7. final ChannelPromise promise = channel.newPromise();
  8. if (regFuture.isDone()) {
  9. doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
  10. } else {
  11. regFuture.addListener(new ChannelFutureListener() {
  12. @Override
  13. public void operationComplete(ChannelFuture future) throws Exception {
  14. doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
  15. }
  16. });
  17. }
  18. return promise;
  19. }

doConnect()方法首先调用了initAndRegister()方法,然后又调用了doConnect0()方法,方法调用示意图如下:

AbstractBootstrap.initAndRegister()

[java] view plain copy

  1. final ChannelFuture initAndRegister() {
  2. final Channel channel = channelFactory().newChannel();
  3. try {
  4. init(channel);
  5. } catch (Throwable t) {
  6. channel.unsafe().closeForcibly();
  7. return channel.newFailedFuture(t);
  8. }
  9. ChannelPromise regPromise = channel.newPromise();
  10. group().register(channel, regPromise);
  11. // ...
  12. }

initAndRegister()方法用ChannelFactory创建了一个Channel的实例,然后调用init()方法初始化Channel,最后将Channel注册到EventLoopGroup上:

而Channel在实例化的时候已经自动关联了Pipeline,这点从AbstractChannel的构造函数可以看出:

[java] view plain copy

  1. protected AbstractChannel(Channel parent) {
  2. this.parent = parent;
  3. unsafe = newUnsafe();
  4. pipeline = new DefaultChannelPipeline(this);
  5. }

Bootstrap.init()方法

[java] view plain copy

  1. void init(Channel channel) throws Exception {
  2. ChannelPipeline p = channel.pipeline();
  3. p.addLast(handler());
  4. // ...
  5. }

Bootstrap.init()方法把Handler添加到了Pipeline的末尾,到这里,Channel就准备就绪了:

继续Bootstrap.doConnect()

initAndRegister()方法结束之后,doConnect()方法紧接着调用了doConnect0()方法,doConnect0()方法继而调用了Channel.connect()方法,这样Channel就接通服务器,可以收发消息了!

时间: 2024-10-30 00:15:29

netty入门02的相关文章

Netty入门二:开发第一个Netty应用程序

    既然是入门,那我们就在这里写一个简单的Demo,客户端发送一个字符串到服务器端,服务器端接收字符串后再发送回客户端. 2.1.配置开发环境 1.安装JDK 2.去官网下载jar包 (或者通过pom构建) 2.2.认识下Netty的Client和Server 一个Netty应用模型,如下图所示,但需要明白一点的是,我们写的Server会自动处理多客户端请求,理论上讲,处理并发的能力决定于我们的系统配置及JDK的极限. Client连接到Server端 建立链接发送/接收数据 Server端

Netty入门之客户端与服务端通信(二)

Netty入门之客户端与服务端通信(二) 一.简介 在上一篇博文中笔者写了关于Netty入门级的Hello World程序.书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码吧. 二.客户端与服务端的通信 2.1 服务端启动程序 public class MyServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup bossGroup = ne

netty入门实例

TimeServer.java package netty.timeserver.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGro

Netty入门之WebSocket初体验

说一说IO通信 BIO通信: BIO即同步阻塞模式一请求一应答的通信模型,该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,由于线程是JAVA虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能将急剧下降,随着并发访问量的继续增大,系统会发生线程堆栈溢出.创建新线程失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务. BIO的服务端通信模型: 采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端

JAVA通信系列三:Netty入门总结

一.Netty学习资料 书籍<Netty In Action中文版> 对于Netty的十一个疑问http://news.cnblogs.com/n/205413/ 深入浅出Nettyhttp://wenku.baidu.com/view/7765bc2db4daa58da0114a4c.html Netty了解与小试 http://www.cnblogs.com/xd502djj/archive/2012/06/25/2561318.html Netty系列之Netty高性能之道[精彩]htt

netty 入门(一)

netty Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更确切的讲是一个组件,没有那么复杂. 例子 一  Discard服务器端 我们先写一个简单的服务端和客户端作为入门,接下来我们在深入介绍里面的内容 :(基于netty4 ) package io.netty.example.discard; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandl

(入门篇 NettyNIO开发指南)第三章-Netty入门应用

作为Netty的第一个应用程序,我们依然以第2章的时间服务器为例进行开发,通过Netty版本的时间服务报的开发,让初学者尽快学到如何搭建Netty开发环境和!运行Netty应用程序. 如果你已经熟悉Netty    的基础应用,可以跳过本章,继续后面知识的学习.本章主要内容包括:.Netty开发环境的搭建.服务端程序TimeServer开发.客户端程序TimeClient开发时间服务器的运行和调试 3.1    Netty开发环境的搭建 首先假设你已经在本机安装了JDKI.7贯配置了JDK的环境

【Netty】NIO框架Netty入门

Netty介绍 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用.Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发. 官网地址:http://netty.io/ 使用场景 Nett

精通并发与Netty入门一:Netty理论知识介绍

Netty是目前无论是国内还是国外各大互联网公司必备的一个网络应用框架.Netty本身既然是网络框架,处理的基本都是与网络相关的这样的一些作用.由于Netty本身在设计上的一些非常巧妙的方式,是对于NIO的一个很好的实现.Netty在各种应用场景下都会得到很广泛的应用.无论是传统的基于http的这种短连接方式还是基于底层Socket的这样的访问方式.另外还支持H5中规范中新增加的一个特别重要的标准,就是关于长连接的websocket这样一种新的规范.Netty对于其提供了非常好的支撑.那么Net