简介
-
netty是一个Java开源框架。提供异步的、事件驱动的网络应用程序的框架和工具,用以快速开发高性能、高可用的网络服务器和客户端程序。
-
netty是一个NIO客户端、服务端框架,允许快速简单的开发网络应用程序。
优点
- api使用简单,开发门槛低。
- 功能强大,预置了很多编解码功能,支持多种主流协议。
- 定制功能强,可以通过ChannelHandler对通信框架进行灵活的扩展。
- 性能高,通过与其他业界主流的NIO框架相比,netty综合性能最优。
- 成熟、稳定,netty已经修复了已经发现的所有bug。
- 社区活跃
- 经历了很多商用考验。
入门代码
public class NettyServer {
public static void main(String[] args) {
//服务端默认端口
int port = 8080;
new NettyServer().bind(port);
}
public void bind(int port) {
//1、用于服务端接收客户端的链接
EventLoopGroup parentGroup = new NioEventLoopGroup();
//2、用于进行SocketChannel的网络读写
EventLoopGroup childGroup = new NioEventLoopGroup();
//netty用于启动NIO服务器的启动类
ServerBootstrap bootstrap = new ServerBootstrap();
//将两个NIO线程组传入辅助启动类中
bootstrap.group(parentGroup, childGroup)
//设置创建的Channel为NioServerSocketChannel类型
.channel(NioServerSocketChannel.class)
//配置NioServerSocketChannel的TCP参数
.option(ChannelOption.SO_BACKLOG, 1024)
//设置绑定IO事件的处理类
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
//创建NIOSocketChannel成功后,在进行初始化时,将它的ChannelHandler设置到ChannelPipeline中,用于处理网络IO事件
ch.pipeline().addLast(new NettyServerHandler());
}
});
try {
//绑定端口,同步等待成功(sync():同步阻塞方法,等待bind操作完成才继续)
//ChannelFuture主要用于异步操作的通知回调
ChannelFuture channelFuture = bootstrap.bind(port).sync();
System.out.println("服务端启动在8080端口。");
//等待服务端监听端口关闭
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//优雅退出,释放线程池资源
parentGroup.shutdownGracefully();
childGroup.shutdownGracefully();
}
}
}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] req = new byte[byteBuf.readableBytes()];
//将buf中数据写入req
byteBuf.readBytes(req);
String body = new String(req, "utf-8");
System.out.println("The time server(Thread:" + Thread.currentThread() + ") receive order : " + body);
String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
//将待发送的消息放到发送缓存数组中
ctx.writeAndFlush(resp);
}
}
public class NettyClient {
public static void main(String[] args) {
new NettyClient().connect("127.0.0.1", 8080);
}
public void connect(String host, int port) {
//配置客户端NIO线程组
EventLoopGroup group = new NioEventLoopGroup();
//配置客户端NIO线程组
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
//创建NIOSocketChannel成功后,在进行初始化时,将它的ChannelHandler设置到ChannelPipeline中,用于处理网络IO事件
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new NettyClientHandler());
}
});
try {
//发起异步连接操作
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
//等待客户端链路关闭
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
/**
* 向服务器发送指令
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
byte[] req = "QUERY TIME ORDER".getBytes();
ByteBuf firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
ctx.writeAndFlush(firstMessage);
}
/**
* 接收服务器的响应
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
//buf.readableBytes():获取缓冲区中可读的字节数;
//根据可读字节数创建数组
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("Now is : " + body);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//释放资源
ctx.close();
}
}