springBoot +netty实现websocket支持URL参数

springBoot +netty实现websocket支持URL参数

需求如下:
1:通过url(ws://ip:端口/?sid=xxxxxxx)形式连接websocket,并且发送数据(自己下面设置的端口,我下面设置端口是8888)
2:每次发送的数据有可能是1M以上。同时每1~2S发送一次数据
3:防止数据泄露等问题。
实现以上需求代码:
  1. 导入架包,注意:netty4.1.6版本底层会报内存泄露。需要我们自己去清空ByteBuf。但是官网说4.1.21版本优化了ByteBuf回收机制。我这使用的netty4.1.25。
    maven导入会自动下载一些依赖的
<dependency>
    <groupId>org.yeauty</groupId>
    <artifactId>netty-websocket-spring-boot-starter</artifactId>
    <version>0.8.0</version>
</dependency>
  1. 搭建通道。使用http格式搭建通道,适用于高并发情况。
public class nettyConfig {
		
		private final int port=8888;  //端口
	
	private void startServer() {
		// 服务端需要2个线程组 boss处理客户端连接 work进行客服端连接之后的处理
		EventLoopGroup boss = new NioEventLoopGroup();
		EventLoopGroup work = new NioEventLoopGroup();
		try {
			ServerBootstrap b = new ServerBootstrap();
			b.group(boss, work).channel(NioServerSocketChannel.class)
            .localAddress(port)
            .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)   //启用池化ByteBuff
	           .childHandler(new ChannelInitializer<SocketChannel>() {
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ChannelPipeline pipeline = ch.pipeline();
							pipeline.addLast(new HttpServerCodec()); // HTTP 协议解析,用于握手阶段
							pipeline.addLast(new ChunkedWriteHandler());
							pipeline.addLast(new HttpObjectAggregator(1024 * 1024 * 100)); 
							pipeline.addLast(new NettyHandler());   //自己业务类
							pipeline.addLast(new WebSocketServerProtocolHandler("/", null, true, 65535*100*100)); // WebSocket// 握手、控制帧处理 
						}
					});
//			 ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.PARANOID);  //用于打印内存是否泄露,如果泄露就会打印具体信息。PARANOID:代表每次发送数据都会检查是否内存泄露(测试时候推荐使用)
			ChannelFuture f = b.bind(port).sync();
			System.out.println(" 启动正在监听: " + f.channel().localAddress());
			f.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭资源
			boss.shutdownGracefully();
			work.shutdownGracefully();
		}
	}

/**
*在程序启动后开启一个线程去启用该方法即可
**/
	@PostConstruct
	public void init() {
		// 需要开启一个新的线程来执行netty server 服务器
		new Thread(new Runnable() {
			public void run() {
				startServer();
			}
		}).start();
		
	}

}
  1. 自己的业务实现类 记住实现这个SimpleChannelInboundHandler类。
@Sharable
public class NettyHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{
/**
	 * 连接websocekt
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println(ctx.channel().id());
		System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());
		super.channelActive(ctx);
	}

	/**
	 * 解析数据。第一次url参数也是走这个方法
	 * 注意:一定要回调父类该方法。不然内存会泄露。不要以为重写该方法后,在最后面添加清除ByteBuf告诉你这是无用的,如果谁成功了请呼唤我。
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
	
				if (null != msg && msg instanceof FullHttpRequest) {
					FullHttpRequest request = (FullHttpRequest) msg;
					log.info("调用 channelRead request.uri() [ {} ]", request.uri());
					String uri = request.uri();
					if (null != uri && uri.contains("/") && uri.contains("?")) {
						String[] uriArray = uri.split("\\?");
						if (null != uriArray && uriArray.length > 1) {
							String[] paramsArray = uriArray[1].split("=");
							if (null != paramsArray && paramsArray.length > 1) {
							//截取出sid后面的值
								verificationConn(ctx, paramsArray[1]); //我自己方法 验证sid值是否符合我这边要求。符合后里面开启心跳等。
							}
						}
						request.setUri("/");
					} else {
						log.info("传参格式有问题 ");
						ctx.close();
					}
				super.channelRead(ctx, msg);    //重新调用父类方法,父类该方法会让ByteBuf	计数清零。从而达到数据被GC回收。如果没有调用该方法内存必会泄露。同时注意:该父类会判断出如果是TextWebSocketFrame 数据类型会调用你重写的channelRead0;具体可以参考源码
	}

/**
*
**/
@Override
	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
		// TODO  处理每次发送过来的数据。
	}
}

以上就是完成这个需求重要的步骤。缺一不可的。剩余的一些业务自己处理即可。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值