简介
Netty我感觉不用太多介绍了,既然搜到了本篇文章,说明你对Netty已经有大体的认识。我就简单的介绍下。
首先Netty是一个高性能框架,单机可以支撑几十万甚至上百万的连接。
Netty 对 JDK 自带的 NIO 的 API 进行了良好的封装,解决了上述问题。且Netty拥有高性能、 吞吐量更高,延迟更低,减少资源消耗,最小化不必要的内存复制等优点。
Netty 现在都在用的是4.x,5.x版本已经废弃,Netty 4.x 需要JDK 6以上版本支持
集成Java
废话不多说,下面进入正题。
第一步
引入pom.xml依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.54.Final</version>
</dependency>
第二步
实现服务端和客户端。
服务端
package com.netty.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer {
public static void main(String[] args) {
// 创建两个线程组bossGroup和workerGroup, 含有的子线程NioEventLoop的个数默认为cpu核数的两倍
// bossGroup只是处理连接请求 ,真正的和客户端业务处理,会交给workerGroup完成
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 创建服务器端的启动对象
ServerBootstrap bootstrap = new ServerBootstrap();
// 使用链式编程来配置参数
bootstrap.group(bossGroup, workerGroup); // 设置两个线程组
bootstrap.channel(NioServerSocketChannel.class); // 使用NioServerSocketChannel作为服务器的通道 实现
// 初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一 个客户端连接。
// 多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
bootstrap.childHandler(new ChannelInitializer<Channel>() {// 创建通道初始化对象,设置初始化参数
@Override
protected void initChannel(Channel ch) throws Exception {
对workerGroup的SocketChannel设置处理器codec
ch.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("netty server start。。");
// 绑定一个端口并且同步, 生成了一个ChannelFuture异步对象,通过isDone()等方法可以判断异步 事件的执行情况
// 启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕
ChannelFuture cf = bootstrap.bind(9000).sync();
// 对通道关闭进行监听,closeFuture是异步操作,监听通道关闭
// 通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成
cf.channel().closeFuture().sync();
} catch (Exception e) {
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
package com.netty.server;
import java.nio.charset.Charset;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
*
* 自定义Handler需要继承netty规定好的某个HandlerAdapter(规范)
*
* @author AdminMall
*
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* 读取客户端发送过来的数据
*
* @param ctx 上下文对象, 含有通道channel,管道pipeline
* @param msg 就是客户端发送的数据
*
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("服务器读取线程" + Thread.currentThread().getName());
// 将 msg 转成一个 ByteBuf,类似NIO 的 ByteBuffer
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("客户端发送的消息为:" + byteBuf.toString(CharsetUtil.UTF_8));
}
/**
* 数据读取完毕处理方法
*
* @param ctx
* @throws Exception
*
*
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// 在数据读取完毕后,向客户端发送消息
ByteBuf buf = Unpooled.copiedBuffer("HelloClient", CharsetUtil.UTF_8);
ctx.writeAndFlush(buf);
}
}
客户端
package com.netty.client;
import com.netty.server.NettyServerHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class NettyClient {
public static void main(String[] args) {
// 客户端需要一个事件循环组
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
// 创建客户端启动对象
// 注意客户端使用的不是 ServerBootstrap 而是 Bootstrap
Bootstrap bootstrap = new Bootstrap();
// 设置相关参数
// 设置线程组
bootstrap.group(eventLoopGroup);
// 使用 NioSocketChannel 作为客户端的通道实现
bootstrap.channel(NioSocketChannel.class);
// 綁定毀掉
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
// 加入处理器
ch.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("netty client start");
// 启动客户端去连接服务器端
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9000).sync();
// 对关闭通道进行监听
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}
package com.netty.client;
import java.nio.charset.Charset;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
*
* 自定义Handler需要继承netty规定好的某个HandlerAdapter(规范)
*
* @author AdminMall
*
*/
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
/**
* 当客户端连接服务器完成就会触发该方法
*
* @param ctx
* @throws Exception
*
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 向服务端发送消息
ByteBuf byteBuf = Unpooled.copiedBuffer("HelloServer", CharsetUtil.UTF_8);
ctx.writeAndFlush(byteBuf);
}
/**
* 读取客户端发送过来的数据
*
* @param ctx 上下文对象, 含有通道channel,管道pipeline
* @param msg 就是客户端发送的数据
*
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 将 msg 转成一个 ByteBuf,类似NIO 的 ByteBuffer
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("服务端发送的消息为:" + byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("服务端地址为:" + ctx.channel().remoteAddress());
}
/**
* 数据读取完毕处理方法
*
* @param ctx
* @throws Exception
*
*
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// 在数据读取完毕后,向客户端发送消息
ByteBuf buf = Unpooled.copiedBuffer("HelloClient", CharsetUtil.UTF_8);
ctx.writeAndFlush(buf);
}
}