SpringBoot集成Netty实现Socket通信(Spring容器托管)
一、开始
注:Socket与WebSocket并不一样。其中Sokcet通过ip:port进行通信,一个ip+port只能实现一条Socket连接,;WebSocket通过ip:port/路径,进行通信,在ip与port一致的情况下,不同的路径可以实现不同的Socket连接
SpringBoot父版本
<parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.5.12</version> <relativePath/> </parent>
|
引入dependencies(需要Web服务的话将spring-boot-starter改成spring-boot-starter-web)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.77.Final</version> </dependency>
|
二、代码配置
application.yml配置netty端口
NettyServer.java(Spring容器托管Netty)
@Slf4j @Component public class NettyServer implements ApplicationRunner, ApplicationListener<ContextClosedEvent>, ApplicationContextAware { @Value("${netty.port}") private Integer port;
private ApplicationContext applicationContext;
private Channel serverChannel;
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }
@Override public void run(ApplicationArguments args) throws Exception { NioEventLoopGroup bossGroup = new NioEventLoopGroup(); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { log.info("------netty新连接:{}------", ch.remoteAddress()); ch.pipeline() .addLast(applicationContext.getBean(MyHandlerAdapter.class)); } }) .option(ChannelOption.SO_BACKLOG, 1024) .childOption(ChannelOption.SO_KEEPALIVE, true);
Channel channel = bootstrap.bind(port).sync().channel(); this.serverChannel = channel; log.info("------netty服务端启动,端口:{}------", port); channel.closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } }
@Override public void onApplicationEvent(ContextClosedEvent event) { if (this.serverChannel != null) { this.serverChannel.close(); } log.info("----------Socket服务停止----------"); } }
|
MyHandlerAdapter.java(Netty消息通信核心部分,自定义实现)
@Slf4j @Component
@ChannelHandler.Sharable public class MyHandlerAdapter extends ChannelInboundHandlerAdapter { @Resource private MsgHeaderDecoder decoder;
@Resource private MsgTypeAndOpt msgTypeAndOpt; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { String id = ctx.channel().id().asLongText(); log.info("连接,id:" + id); }
@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { log.info("断开"); ctx.channel().close(); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] bytes = new byte[buf.readableBytes()]; buf.readBytes(bytes); }
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { log.info("用户事件"); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception { log.info("发生异常"); e.printStackTrace(); ctx.channel().close(); } }
|