Netty,之前听过一句话,不会Netty,别说你是Java高级。这玩意到底是啥呢?

各种资料看了下,原来就是一款框架啊。为了网络编程而生。和java中的套接字有得一比。

既然是框架,设计思想很重要。

我们来了解下:

Netty


Netty是一款Java框架,用于快速开发高性能的网络应用,


它封装了网络编程的复杂性.


使用 apache maven作为它的管理工具


Netty是一款框架,设计原则: 每个小点都和它的技术性一样重要,穷奇精妙。


Java既有的网络编程的局限


java.net包只提供了一套使用本地系统套接字库提供的阻塞函数



也就是 创建网络编程需要安装如下的步骤进行:



监听某个端口,创建一个 ServerSocket


ServerSocket serverSocket = new ServerSocket(portNumber) ;


然后 使用 accept方法得到一个 客户端的套接字


Socket clientSocket = serverSocket.accept();



这样clientSocket就和 serverSocket进行通信了


使用 clientSocket的流处理可以进行数据的传输


BufferedReder bi = new BufferedReader(


new InpustStreamReader(clientSocket.getInpu·stStream())


);



PrintWriter pw = new PrintWriter(clientSocket.getOutputStream());



使用流就可以进行处理了


传统的java的套接字的缺陷


我们可以看到这种代码同时只能处理一个连接,如果要管理多个客户端的时候,就要给每个客户端的


socket创建一个线程来处理.


这样问题转换为了多线程。


但是如果连接数目很高的时候,线程直接的管理以及创建,切换等管理遇到的问题就很尖锐了.




netty java项目 java netty socket_套接字





采用多线程进行处理的特点就是消耗内存


通过多个并发的线程来达到高并发的目的。


Netty的处理


netty使用一个 选择器来进行,使这个多线程的处理转变为单线程的处理


netty使用的是 nio 非阻塞io 的使用 non blocking i/o


这个思想是借鉴与 函数式编程的 例如 nodejs的并发实现,


采用 单线程但是 消耗cpu计算能力来得到的高并发


因此这种机制是 事件驱动型的



java.nio.channels.Selector


netty java项目 java netty socket_java_02



异步和事件驱动


nodejs使用 的异步,函数式编程思想,单线程的处理,消耗cpu计算达到 高并发处理



异步: 非阻塞,非阻塞网络调用使我们可以不必等待一个操作完成


nio的选择器使我们能够通过很少的线程便可以监视许多链接上的事件。



从这里引出了 Netty 的 特性 :


异步,模仿的nodejs的处理方式,因此是 事件驱动型的



事件,回调,channel 等等



异步的特性: 事情处理完了要想办法通知主程序



回调函数是一种通知方式。


Netty中的 Future也是一种通知的方式


Netty的核心组件

  1. channel
  2. 回调
  3. Future
  4. 事件和ChannelHandler

channel


channel是java nio 的一个基本构造


表示一个到实体的开放链接,


这个实体可以是:


  • 硬件设备
  • 文件
  • 网路套接字
  • 能够执行 io操作的组件


和其名字一样,表示一个 渠道,管道,和上面的实体链接之后,那么就是上面这些实体的数据的载体。


我们对实体的数据以及实体数据的传出都是用这个channel


回调--ChannelHandler


这个不陌生了,js的异步特性中的回调函数.



所以回调本身表示一个 方法 , 也就是该方法的引用提供给另外一个方法。


在c中可以认为是函数的指针,js中就是函数的句柄,java中函数是存在于对象上的,


因此可以使用包装该函数的接口对象



Netty内部使用 回调来处理事件响应。(监听器注册一个函数,当事件触发的时候就回调一个函数)


接口 ChannelHandler来处理的


该接口中有一个 channelActive方法,这个就是一个回调函数


这个类似于 awt编程中的 ActionLiistener的 actionPerformed函数一样。



可以类比: 当一个channel链接到一个实体的时候,那么同时注册这个channel对应的处理


channelHandler的接口函数,一旦有事件出现的时候,就会调用这个函数进行事件的处理


这个方法的签名是:


public void channelActive(ChannelHandlerContext ctx)



ChannelHandlerContext 就是我们获取当前channel的媒介


Future


Future提供了另外一种在操作完成时候通知应用程序的方式


这个对象可以看作是一个 异步操作结果的占位符。它将在未来某个时刻完成并提供对其结果的访问.



Future 接口


JDK 是提供了Future的


java.util.concurrent.Future 接口,但是它提供的实现是只能手动的检查对应的操作是否完成



ChannelFuture实现类


ChannelFuture , 用于在执行异步操作的时候使用


这个 ChannelFuture的实现是借鉴于 Action Listener的



ChannelFutureListener 监听器


ChannelFuture 提供了几种不同的方法可以注册一个或注册多个


ChannelFutureListener的实例,同样监听器有自己的回调方法的---operationComplete()


这个很类似于 actionPerformed方法.



public void operationComplete(ChannelFuture future)



可以想象 这个 ChannelFuture和我们的 awt中的 Button是很类似的


他们都可以注册监听器,监听器中封装了回调方法



每个netty的出站 I/O操作 都将返回一个 ChannelFuture 对象.


这样每个I/O操作都不阻塞.



如下的模式进行操作:


  1. 获取channel
  2. 使用channel异步连接远程节点,得到channelfuture
  3. 使用channelfuture注册监听 channelfuturelistener
  4. 实现listener的回调函数 operationComplete方法

Channel channel = ... 

 

  ChannelFuture future = channel.concet (new InetSocketAddress("192.168.0.1",25)); 

 

  future.addListner(new ChannelFutureListener() { 

 
operationComplete(  ChannelFuture future) { 

 

  if(future.isSuccess()) { 

 
 

 

  } else { 

 

  Throwable cause = future.cause(); 

 

  } 

 

  } 

 

  });


我们可以看到每一个 channelfuture都将会注册一个 channelfutureListener


ChannelFuture


也就是说可以识别到底是哪一个future的监听结果



事件和ChannelHandler


Netty是基于事件触发的,会通过各种各样的事件通知我们程序的状态


Netty是一个网络编程框架,事件是安装入站和出站数据流的相关性进行分类的



入站事件


连接已被激活或者连接失活


数据读取


用户事件


错误事件




出站事件


打开或关闭远程节点连接


将数据写入或冲刷套接字



每个事件都被分发给 用户实现的 ChannelHandler接口方法



综合


Netty的异步编程是基于 Future 和 回调函数的


而且是事件驱动的


但是每个事件分配给FutureHandler是更深层次的东西。


因为事件很多,因此Netty提供了很多重要的 FutureHandler


而且在内部,FutureHandler也使用了很多的事件和Future



ChannelFuture和回调是相互补充的机制。


ChannelFutureListener是一个精细的回调



No1 Future , 回调 , ChannelHandler


No2 选择器,事件 , EventLoop



选择器 就是来进行事件派发的操作,Netty将选择器给抽象出来了


而且 为每个 channel 分配一个 EventLoop,用于处理所有事件



EventLoop


EventLoop是一个线程驱动,这个和nodejs的循环事件一样


它将处理一个channel的所有I/o