本文目录
1. 简介
直接使用底层的API暴露了复杂性,并且引入了对往往供不应求的技能的关键性依赖。这也就是,面向对象的基本概念:用较简单的抽象隐藏底层实现的复杂性。
在网络编程领域,Netty是Java的卓越框架。它驾驭了Java高级API的能力,并将其隐藏在一个易于使用的API之后。Netty的关键特征,
分类 | 特征 |
---|---|
设计 | 统一的 API,支持多种传输类型,阻塞的和非阻塞的;简单而强大的线程模型;真正的无连接数据报套接字支持;链接逻辑组件以支持复用 |
易于使用 | 详实的Javadoc和大量的示例集不需要超过JDK 1.6+③的依赖。(一些可选的特性可能需要Java 1.7+和/或额外的依赖) |
性能 | 拥有比 Java 的核心 API 更高的吞吐量以及更低的延迟;得益于池化和复用, 拥有更低的资源消耗;最少的内存复制 |
健壮性 | 不会因为慢速、快速或者超载的连接而导致 OutOfMemoryError;消除在高速网络中 NIO 应用程序常见的不公平读/写比率 |
安全性 | 完整的 SSL/TLS 以及 StartTLS 支持可用于受限环境下,如 Applet 和 OSGI |
社区驱动 | 发布快速而且频繁 |
2. 核心组成
2.1 Channel
Channel 是 Java NIO 的一个基本构造。它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件) 的开放连接,如读操作和写操作。目前,可以把 Channel 看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。
2.2 EventLoop 和 EventLoopGroup
Netty 通过触发事件将 Selector 从应用程序中抽象出来,消除了所有本来将需要手动编写的派发代码。 在内部,将会为每个 Channel 分配一个 EventLoop, 用以处理所有事件, 包括:1)注册感兴趣的事件;2)将事件派发给 ChannelHandler;3)安排进一步的动作。
EventLoop 本身只由一个线程驱动,其处理了一个 Channel 的所有 I/O 事件,并且在该
EventLoop 的整个生命周期内都不会改变。这个简单而强大的设计消除了你可能有的在
ChannelHandler 实现中需要进行同步的任何顾虑,因此, 你可以专注于提供正确的逻辑,用来在有感兴趣的数据要处理的时候执行。如同我们在详细探讨 Netty 的线程模型时将会看到的,该 API 是简单而紧凑的。EventLoopGroup真是由EventLoop组成的一个组。
2.3 ChannelPipeline 和 ChannelHandler
目前可以认为每个 ChannelHandler 的实例都类似于一种为了响应特定事件而被执行的回调。Netty 提供了大量预定义的可以开箱即用的 ChannelHandler 实现,包括用于各种协议(如 HTTP 和 SSL/TLS)的 ChannelHandler。在内部, ChannelHandler 自己也使用了事件和 Future,使得它们也成为了你的应用程序将使用的相同抽象的消费者。
而ChannelPipeline 是 ChannelHandler 的容器, 它负责 ChannelHandler 的管理和事件拦截与调度。
2.4 引导
引导类为应用程序的网络层配置提供了容器,这涉及将一个进程绑定到某个指定的端口, 或者将一个进程连接到另一个运行在某个指定主机的指定端口上的进程。
3. Netty Demo
服务端代码:
package com.linfo.netty.helloExample;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
/**
* Created by linfeng
*/
public class serverDemo {
private int port;
public serverDemo(int port) {
this.port = port;
}
public static void main(String[] args) {
new serverDemo(8088).start();
}
public void start() {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap = bootstrap.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
public void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new helloHandler());
}
});
try {
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println("listen port: " + port);
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
@ChannelHandler.Sharable
class helloHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext context, Object msg) {
ByteBuf in = (ByteBuf) msg;
System.out.println("server received a message...");
System.out.println(context.channel().remoteAddress() + " -> server : " + in.toString(CharsetUtil.UTF_8));
context.write("server has received message server -> client : " + in.toString(CharsetUtil.UTF_8) );
context.flush();
System.out.flush();
}
@Override
public void channelReadComplete(ChannelHandlerContext context) {
context.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext context, Throwable cause) {
cause.printStackTrace();
context.close();
}
}
}
客户端代码:
package com.linfo.netty.helloExample;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
/**
* Created by linfeng
*/
public class clientDemo {
private final static String HOST = "127.0.0.1";
private final static int PORT = 8088;
public static void main(String[] args) {
new clientDemo().start();
}
public void start() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap = bootstrap.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(HOST, PORT))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) {
channel.pipeline().addLast(new helloClientHandler());
}
});
ChannelFuture future = bootstrap.connect().sync();
//future.channel().writeAndFlush("Hello server this is a message, I am Client");
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
@ChannelHandler.Sharable
class helloClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
public void channelActive(ChannelHandlerContext channelHandlerContext) {
channelHandlerContext.writeAndFlush(Unpooled.copiedBuffer("First message", CharsetUtil.UTF_8));
}
@Override
public void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println("Client received:" + byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable cause) {
cause.printStackTrace();
channelHandlerContext.close();
}
}
}
To be continue