netty简介
netty是一款高性能的网络应用框架,相比较原生的socket编程,它的api更加简单、易用,它对原生的tcp connection进行了包装,提供了channel、channelhandler、编解码器等概念。
线程组
netty中的线程组包括bossgroup和workergroup,顾名思义bossgroup是用来接收connection(可简单认为是tcp connection),workergroup用来处理已经建立好的connection,收发数据。通俗点说,tcp的三次握手是bossgroup负责的;tcp connection建立后,交给workergroup处理;bossgroup相当于前台接待,登记好信息后,由服务员服务客户。
- server端,有bossgroup、workergroup;client端,只有workergroup。
- channel,抽象了connection,有bind、connect
- pipeline,管线包含了很多handler,类似java servlet中的filter链,是链式处理的
- channelhandler,处理器
- 从处理器中细分出来的 decoder、encoder,也是一种handler,以接收端处理数据为例,通常先由decoder解码,再由handler处理;有些开箱即用的encoder,比如MessageToByteEncoder;
- 粘包拆包的由来
socket有个socket接收缓冲区,发送过来的是packet队列,但缓冲区是字节队列,所以,应用层拿到的数据与发送的数据很大概率是不一样的,会packet fragmentation(碎片)还有defrag(碎片整理),所以要注意处理。
常见问题
- 客户端收不到响应
wirteandflush(bytes[]) 默认的只对bytebuf编码,写入到远端,所以需要新增一个ByteArrayEncoder
//配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup(1);//用于处理服务器端接收客户端连接
EventLoopGroup workerGroup = new NioEventLoopGroup();//进行网络通信(读写)
ServerBootstrap b = new ServerBootstrap();//辅助工具类,用于服务器通道的一系列配置
b.group(workerGroup, bossGroup) // 绑定线程池
// 指定使用的channel
.channel(NioServerSocketChannel.class)
//标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度
.option(ChannelOption.SO_BACKLOG, 1024)
// 使消息立即发出去,不用等待到一定的数据量才发出去
.childOption(ChannelOption.TCP_NODELAY, true)
// 保持长连接状态
.childOption(ChannelOption.SO_KEEPALIVE, true)// 2小时无数据激活心跳机制
.childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
//新增空闲处理器
.addLast(new IdleStateHandler())
//新增编码器
.addLast(new ByteArrayEncoder()); // 客户端触发操作
}
});
- spring 集成netty后阻塞主线程
- 利用spring application中的CommandLineRunner 扩展点执行启动nettyserver,但这样仍然与spring使用的同一个线程,可以新建一个Thread启动NettyServer
public class MyApplication implements CommandLineRunner {
@Autowired
private SocketServer socketServer;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
//新开线程启动
new Thread(() -> {
socketServer.start();
}).start();
}
}
- 不能跨channel使用
- netty handler纳入spring管理 ,handler中通常会调用service,所以handler也要纳入spring管理,而handler通常是一个channel一个handler,不能跨channel使用,添加注解@ChannelHandler.Sharable
@ChannelHandler.Sharable
public class SocketServerChannelHandler extends SimpleChannelInboundHandler<ByteBuf> {}
- 监控channel状态
netty提供了idlestatehandler,它负责来监控channel状态,如果状态发生变化,则触发event;