Netty的介绍
Netty 是一个高性能、异步事件驱动的 NIO 框架,基于 JAVA NIO 提供的 API 实现。
Netty的使用
Netty的模板代码
netty开发基本上都是基于固定的模板代码进行开发
三行核心代码,
1. 初始化Bootstrap
2. 链式方式配置参数
3. 启动并绑定端口
业务处理会放在Handler里,可以自定义
- 服务端代码
import io.netty.bootstrap.ServerBootstrap;
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;
import io.netty.channel.socket.nio.NioSocketChannel;
public class NettyServer {
public static void main(String[] args) {
//创建两个线程组bossGroup和workGroup,含有的子线程NioEventLoopGroup的个数默认为cpu核数的两倍
//bossGroup只是处理连接请求,真正的和客户端业务处理,会交给workGroup完成
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try{
//创建一个ServerBootstrap,用于服务器引导辅助类
ServerBootstrap bootstrap = new ServerBootstrap();
//使用链式编程来配置参数
bootstrap.group(bossGroup,workGroup) //设置两个线程组
//设置NioServerSocketChannel作为服务器的通道实现
.channel(NioServerSocketChannel.class)
//初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只处理一个客户端连接
//多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
//对workerGroup的SocketChannel设置处理器
ch.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("netty sever start...");
//绑定一个端口并且同步,生成一个ChannelFuture异步对象,通过isDone()方法判断异步方法执行情况
//启动服务器,绑定端口,bind是异步绑定,sync()方法会阻塞等待直到绑定成功
ChannelFuture future = bootstrap.bind(8080).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//关闭EventLoopGroup,释放掉所有资源
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
- 自定义的Handler,这里实现对数据的处理
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.nio.charset.StandardCharsets;
/**
* 自定义Handler需要继承netty规定好的某个HandlerAdapter(规范)
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* 当客户端连接服务器完成就会触发该方法
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
}
/**
* 当客户端发送消息到服务器时会触发该方法
* @param ctx 上下文对象,含有通道channel,管道pipeline
* @param msg 客户端发送的数据
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//将客户端发送的数据转换为ByteBuf,类似NIO的ByteBuffer
ByteBuf buf = (ByteBuf) msg;
//如果要发送String类型,需要在pipeline中加入字符串的编码解码器,可以继续调用监听回写成功与否的API
ctx.channel().writeAndFlush(buf);
System.out.println("服务器接收到的数据:" + buf.toString(StandardCharsets.UTF_8));
}
/**
* 1.客户端发送关闭帧 2.客户端结束进程 3.服务端主动调用channel.close()时调用
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
}
}
- 完成以上服务端代码可以使用telnet命令进行测试一下
- netty也有客户端的模板代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import java.net.InetSocketAddress;
public class HelloClient {
public static void main(String[] args) throws InterruptedException {
//创建启动器类
new Bootstrap()
//添加eventLoop
.group(new NioEventLoopGroup())
//选择客户端channel事件
.channel(NioSocketChannel.class)
//添加处理器
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override //在连接之后调用
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
}
})
//连接到服务器
.connect(new InetSocketAddress("localhost",8080))
.sync()//阻塞方法直到连接
.channel()//代表连接对象
//向服务器发送数据
.writeAndFlush("hello world");
}
}
- 解析协议时要在pipeline加入相应协议的解码器
- String转ByteBuf
ByteBuf buf = Unpooled.wrappedBuffer(bytes);