Netty基础

Posted by kyle on June 23, 2018

Netty核心组件

  • Channel
  • 回调
  • Future
  • 事件和ChannelHandler

Channel

Channel是Java NIO的一个基本构造。

它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作。

可以把Channel看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者关闭,连接或者断开连接。

回调

一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。这使得接受回调的方法可以在适当的时候调用被回调的方法。

Netty在内部使用了回调来处理事件,当一个回调被触发时,相关的事件可以被一个Interface——ChannelHandler的实现处理。

代码示例:

public class ConnectHandler extends ChannelInboundHandlerAdapter {
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("Client " + ctx.channel().remoteAddress() + " connected");
	}
}

Funture

Future提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。

JDK预置了interface java.util.concurrent.Future,但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以Netty提供了它自己的实现——ChannelFuture,用于在执行异步操作的时候使用。

ChnnelFuture提供了几种额外的方法,这些方法使得我们能够注册一个或者多个ChannelFutureListener实例。监听器的回调方法operationComplete(),将会在对应的操作完成时被调用。然后监听器可以判断该操作是成功地完成了还是出错了。如果是后者,我们可以检索产生的Throwable。简而言之,由ChannelFutureListener提供的通知机制消除了手动检查对应的操作是否完成的必要。

每个Netty的出站I/O操作都将返回一个ChannelFuture;也就是说,他们都不会阻塞。

以下代码示例展示了一个ChannelFuture作为一个I/O操作的一部分返回的例子以及如何利用ChannelFutureListener。这里connect()方法将会直接返回,而不会阻塞,该调用将会在后台完成。

Channel channel = ...;

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

future.addListener(new ChannelFutureListener() {
	@Override
	public void operationComplete(ChannelFuture future) {
		if(future.isSuccess()) {
			ByteBuf buffer = Unpooled.copiedBuffer("Hello", Charset.defaultCharset());
			ChannelFuture wf = future.channel().writeAndFlush(buffer);
			....
		} else {
			Throwable cause = future.cause();
			cause.printStackTrace();
		}
	}
})

可以把ChannelFutureListener看作是回调的一个更加精细的版本。事实上,回调和Future是相互补充的机制。

事件和ChannelHandler

Netty使用不同的事件来通知我们状态的改变或者是操作的改变。这使得我们能够基于已经发生的事件来触发适当的动作。这些动作可能是:

  • 记录日志
  • 数据转换
  • 流控制
  • 应用程序逻辑

Netty是一个网络编程框架,所以事件是按照它们与入站或出站数据流的相关性进行分类的。

与入站相关的事件 与出站相关的事件
连接已被激活或者连接失活 打开或者关闭到远程节点的连接
数据读取 将数据写到或者冲刷到套接字
用户事件  
错误事件  

每个事件都可以被分发给ChannelHandler类中的某个用户实现的方法。