netty——LengthFieldBasedFrameDecoder实例(解决半包)



1,使用LengthFieldPrepender编码,LengthFieldBasedFrameDecoder解码的netty传输

可以解决半包粘包

2 代码部分

tcpserver

[java]  view plain  copy
 print ?
  1. package com.bimatrix.revit.nettyTest;  
  2.   
  3. import io.netty.bootstrap.ServerBootstrap;  
  4. import io.netty.channel.ChannelFuture;  
  5. import io.netty.channel.ChannelInitializer;  
  6. import io.netty.channel.ChannelPipeline;  
  7. import io.netty.channel.EventLoopGroup;  
  8. import io.netty.channel.nio.NioEventLoopGroup;  
  9. import io.netty.channel.socket.SocketChannel;  
  10. import io.netty.channel.socket.nio.NioServerSocketChannel;  
  11. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;  
  12. import io.netty.handler.codec.LengthFieldPrepender;  
  13. import io.netty.handler.codec.string.StringDecoder;  
  14. import io.netty.handler.codec.string.StringEncoder;  
  15. import io.netty.util.CharsetUtil;  
  16.   
  17. import org.apache.log4j.Logger;  
  18.     
  19. public class TcpServer {    
  20.     
  21.     private static final Logger logger = Logger.getLogger(TcpServer.class);    
  22.     private static final String IP = "127.0.0.1";    
  23.     private static final int PORT = 9999;    
  24.     /**用于分配处理业务线程的线程组个数 */    
  25.     protected static final int BIZGROUPSIZE = Runtime.getRuntime().availableProcessors()*2//默认    
  26.     /** 业务出现线程大小*/    
  27.     protected static final int BIZTHREADSIZE = 4;    
  28.         /*  
  29.      * NioEventLoopGroup实际上就是个线程池,  
  30.      * NioEventLoopGroup在后台启动了n个NioEventLoop来处理Channel事件,  
  31.      * 每一个NioEventLoop负责处理m个Channel,  
  32.      * NioEventLoopGroup从NioEventLoop数组里挨个取出NioEventLoop来处理Channel  
  33.      */    
  34.     private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);    
  35.     private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);    
  36.         
  37.     protected static void run() throws Exception {    
  38.         ServerBootstrap b = new ServerBootstrap();    
  39.         b.group(bossGroup, workerGroup);    
  40.         b.channel(NioServerSocketChannel.class);    
  41.         b.childHandler(new ChannelInitializer<SocketChannel>() {    
  42.             @Override    
  43.             public void initChannel(SocketChannel ch) throws Exception {    
  44.                 ChannelPipeline pipeline = ch.pipeline();    
  45.                 pipeline.addLast("frameDecoder"new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0404));    
  46.                 pipeline.addLast("frameEncoder"new LengthFieldPrepender(4));    
  47.                 pipeline.addLast("decoder"new StringDecoder(CharsetUtil.UTF_8));    
  48.                 pipeline.addLast("encoder"new StringEncoder(CharsetUtil.UTF_8));    
  49.                 pipeline.addLast(new TcpServerHandler());    
  50.             }    
  51.         });    
  52.     
  53.         // b.bind(IP, PORT).sync();    
  54.         ChannelFuture f = b.bind(PORT).sync(); // (7)  
  55.   
  56.   
  57.         f.channel().closeFuture().sync();  
  58.           
  59.           
  60.         logger.info("TCP服务器已启动");    
  61.     }    
  62.         
  63.     protected static void shutdown() {    
  64.         workerGroup.shutdownGracefully();    
  65.         bossGroup.shutdownGracefully();    
  66.     }    
  67.     
  68.     public static void main(String[] args) throws Exception {    
  69.         logger.info("开始启动TCP服务器...");    
  70.         TcpServer.run();    
  71. //      TcpServer.shutdown();    
  72.     }    
  73. }    

TcpServerHandler

[java]  view plain  copy
 print ?
  1. package com.bimatrix.revit.nettyTest;  
  2.   
  3.   
  4.   
  5. import io.netty.channel.ChannelHandlerAdapter;  
  6. import io.netty.channel.ChannelHandlerContext;  
  7.     
  8. public class TcpServerHandler extends ChannelHandlerAdapter  {    
  9.     
  10.     @Override  
  11.     public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)  
  12.        ctx.write(msg); // (1)  
  13.        String obj= (String)msg;  
  14.        System.out.println("访问数据"+obj);  
  15.       // ctx.write(obj); // (1)  
  16.        ctx.flush(); // (2)  
  17.   
  18.     }  
  19.   
  20.     @Override  
  21.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)  
  22.   
  23.        // Close theconnection when an exception is raised.  
  24.        cause.printStackTrace();  
  25.        ctx.close();  
  26.     }  
  27.     @Override  
  28.     public void channelActive(final ChannelHandlerContext ctx) {  
  29.             ctx.writeAndFlush("有客户端连接"); // (3)  
  30.     }  
  31.     
  32. }    

TcpClientHander

[java]  view plain  copy
 print ?
  1. <span style="font-size:18px;">package com.bimatrix.revit.nettyTest;  
  2.   
  3. import io.netty.channel.ChannelHandlerAdapter;  
  4. import io.netty.channel.ChannelHandlerContext;  
  5.   
  6. public class TcpClientHandler extends ChannelHandlerAdapter {    
  7.     public TcpClientHandler() {    
  8.     }    
  9.     //private byte[] req;  
  10.     /**  
  11.      * 链路链接成功  
  12.      */    
  13.     @Override    
  14.     public void channelActive(ChannelHandlerContext ctx) throws Exception {    
  15.         /*for (int i = 0; i < 1000; i++) { 
  16.             ctx.writeAndFlush("1ac"); 
  17.         } */  
  18.         // 链接成功后发送    
  19.     }    
  20.     
  21.     @Override    
  22.     public void channelRead(ChannelHandlerContext ctx, Object msg)    
  23.             throws Exception {    
  24.          System.out.println("client收到数据" +msg);  
  25. //       ctx.write("收到数据!");   
  26. //       ctx.write(msg);   
  27. //       ctx.write("w2d");   
  28.     
  29.     }    
  30.     
  31.     @Override    
  32.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {    
  33.         ctx.flush();    
  34.     }    
  35.     
  36.     @Override    
  37.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)    
  38.             throws Exception {    
  39.         cause.printStackTrace();    
  40.         ctx.close();    
  41.     }    
  42. }  </span>  



TcpClient

[java]  view plain  copy
 print ?
  1. package com.bimatrix.revit.nettyTest;  
  2.   
  3. import io.netty.bootstrap.Bootstrap;    
  4. import io.netty.channel.Channel;    
  5. import io.netty.channel.ChannelInitializer;    
  6. import io.netty.channel.ChannelOption;    
  7. import io.netty.channel.ChannelPipeline;    
  8. import io.netty.channel.EventLoopGroup;    
  9. import io.netty.channel.nio.NioEventLoopGroup;    
  10. import io.netty.channel.socket.nio.NioSocketChannel;    
  11. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;    
  12. import io.netty.handler.codec.LengthFieldPrepender;    
  13. import io.netty.handler.codec.string.StringDecoder;    
  14. import io.netty.handler.codec.string.StringEncoder;    
  15. import io.netty.util.CharsetUtil;    
  16.     
  17. import org.apache.log4j.Logger;    
  18.     
  19. public class TcpClient {    
  20.     private static final Logger logger = Logger.getLogger(TcpClient.class);    
  21.     public static String HOST = "127.0.0.1";    
  22.     public static int PORT = 9999;    
  23.         
  24.     public static Bootstrap bootstrap = getBootstrap();    
  25.     public static Channel channel = getChannel(HOST,PORT);    
  26.     /**  
  27.      * 初始化Bootstrap  
  28.      * @return  
  29.      */    
  30.     public static final Bootstrap getBootstrap(){    
  31.         EventLoopGroup group = new NioEventLoopGroup();    
  32.         Bootstrap b = new Bootstrap();    
  33.         b.group(group).channel(NioSocketChannel.class);    
  34.         b.handler(new ChannelInitializer<Channel>() {    
  35.             @Override    
  36.             protected void initChannel(Channel ch) throws Exception {    
  37.                 ChannelPipeline pipeline = ch.pipeline();    
  38.                 pipeline.addLast("frameDecoder"new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0404));    
  39.                 pipeline.addLast("frameEncoder"new LengthFieldPrepender(4));    
  40.                 pipeline.addLast("decoder"new StringDecoder(CharsetUtil.UTF_8));    
  41.                 pipeline.addLast("encoder"new StringEncoder(CharsetUtil.UTF_8));    
  42.                 pipeline.addLast("handler"new TcpClientHandler());    
  43.             }    
  44.         });    
  45.         b.option(ChannelOption.SO_KEEPALIVE, true);    
  46.         return b;    
  47.     }    
  48.     
  49.     public static final Channel getChannel(String host,int port){    
  50.         Channel channel = null;    
  51.         try {    
  52.             channel = bootstrap.connect(host, port).sync().channel();    
  53.         } catch (Exception e) {    
  54.             logger.error(String.format("连接Server(IP[%s],PORT[%s])失败", host,port),e);    
  55.             return null;    
  56.         }    
  57.         return channel;    
  58.     }    
  59.     
  60.     public static void sendMsg(String msg) throws Exception {    
  61.         if(channel!=null){    
  62.             channel.writeAndFlush(msg).sync();    
  63.         }else{    
  64.             logger.warn("消息发送失败,连接尚未建立!");    
  65.         }    
  66.     }    
  67.     
  68.     public static void main(String[] args) throws Exception {  
  69.    
  70.         try {    
  71.             long t0 = System.nanoTime();    
  72.             for (int i = 0; i < 100000; i++) {   
  73.                 if(i%3==0){  
  74.                      TcpClient.sendMsg(i+"11aaa222aaa");   
  75.                 }else if(i%3==1){  
  76.                      TcpClient.sendMsg(i+"222cccdddbbbbbbbbbbbb");   
  77.                 }else if(i%3==2){  
  78.                  TcpClient.sendMsg(i+"333cccddda12ccccccccccccccccccccccccc");   
  79.                 }  
  80.             }    
  81.             long t1 = System.nanoTime();    
  82.             System.out.println((t1-t0)/1000000.0);    
  83.         } catch (Exception e) {    
  84.             e.printStackTrace();    
  85.         }    
  86.     }    
  87. }    


上面代码部分下面这一块 主要测试消息发送是否会造成粘包
 for (int i = 0; i < 100000; i++) { 
             if(i%3==0){
             TcpClient.sendMsg(i+"11aaa222aaa"); 
             }else if(i%3==1){
             TcpClient.sendMsg(i+"222cccdddbbbbbbbbbbbb"); 
             }else if(i%3==2){
            TcpClient.sendMsg(i+"333cccddda12ccccccccccccccccccccccccc"); 
             }
            }  

1,使用LengthFieldPrepender编码,LengthFieldBasedFrameDecoder解码的netty传输

可以解决半包粘包

2 代码部分

tcpserver

[java]  view plain  copy
 print ?
  1. package com.bimatrix.revit.nettyTest;  
  2.   
  3. import io.netty.bootstrap.ServerBootstrap;  
  4. import io.netty.channel.ChannelFuture;  
  5. import io.netty.channel.ChannelInitializer;  
  6. import io.netty.channel.ChannelPipeline;  
  7. import io.netty.channel.EventLoopGroup;  
  8. import io.netty.channel.nio.NioEventLoopGroup;  
  9. import io.netty.channel.socket.SocketChannel;  
  10. import io.netty.channel.socket.nio.NioServerSocketChannel;  
  11. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;  
  12. import io.netty.handler.codec.LengthFieldPrepender;  
  13. import io.netty.handler.codec.string.StringDecoder;  
  14. import io.netty.handler.codec.string.StringEncoder;  
  15. import io.netty.util.CharsetUtil;  
  16.   
  17. import org.apache.log4j.Logger;  
  18.     
  19. public class TcpServer {    
  20.     
  21.     private static final Logger logger = Logger.getLogger(TcpServer.class);    
  22.     private static final String IP = "127.0.0.1";    
  23.     private static final int PORT = 9999;    
  24.     /**用于分配处理业务线程的线程组个数 */    
  25.     protected static final int BIZGROUPSIZE = Runtime.getRuntime().availableProcessors()*2//默认    
  26.     /** 业务出现线程大小*/    
  27.     protected static final int BIZTHREADSIZE = 4;    
  28.         /*  
  29.      * NioEventLoopGroup实际上就是个线程池,  
  30.      * NioEventLoopGroup在后台启动了n个NioEventLoop来处理Channel事件,  
  31.      * 每一个NioEventLoop负责处理m个Channel,  
  32.      * NioEventLoopGroup从NioEventLoop数组里挨个取出NioEventLoop来处理Channel  
  33.      */    
  34.     private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);    
  35.     private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);    
  36.         
  37.     protected static void run() throws Exception {    
  38.         ServerBootstrap b = new ServerBootstrap();    
  39.         b.group(bossGroup, workerGroup);    
  40.         b.channel(NioServerSocketChannel.class);    
  41.         b.childHandler(new ChannelInitializer<SocketChannel>() {    
  42.             @Override    
  43.             public void initChannel(SocketChannel ch) throws Exception {    
  44.                 ChannelPipeline pipeline = ch.pipeline();    
  45.                 pipeline.addLast("frameDecoder"new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0404));    
  46.                 pipeline.addLast("frameEncoder"new LengthFieldPrepender(4));    
  47.                 pipeline.addLast("decoder"new StringDecoder(CharsetUtil.UTF_8));    
  48.                 pipeline.addLast("encoder"new StringEncoder(CharsetUtil.UTF_8));    
  49.                 pipeline.addLast(new TcpServerHandler());    
  50.             }    
  51.         });    
  52.     
  53.         // b.bind(IP, PORT).sync();    
  54.         ChannelFuture f = b.bind(PORT).sync(); // (7)  
  55.   
  56.   
  57.         f.channel().closeFuture().sync();  
  58.           
  59.           
  60.         logger.info("TCP服务器已启动");    
  61.     }    
  62.         
  63.     protected static void shutdown() {    
  64.         workerGroup.shutdownGracefully();    
  65.         bossGroup.shutdownGracefully();    
  66.     }    
  67.     
  68.     public static void main(String[] args) throws Exception {    
  69.         logger.info("开始启动TCP服务器...");    
  70.         TcpServer.run();    
  71. //      TcpServer.shutdown();    
  72.     }    
  73. }    

TcpServerHandler

[java]  view plain  copy
 print ?
  1. package com.bimatrix.revit.nettyTest;  
  2.   
  3.   
  4.   
  5. import io.netty.channel.ChannelHandlerAdapter;  
  6. import io.netty.channel.ChannelHandlerContext;  
  7.     
  8. public class TcpServerHandler extends ChannelHandlerAdapter  {    
  9.     
  10.     @Override  
  11.     public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)  
  12.        ctx.write(msg); // (1)  
  13.        String obj= (String)msg;  
  14.        System.out.println("访问数据"+obj);  
  15.       // ctx.write(obj); // (1)  
  16.        ctx.flush(); // (2)  
  17.   
  18.     }  
  19.   
  20.     @Override  
  21.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)  
  22.   
  23.        // Close theconnection when an exception is raised.  
  24.        cause.printStackTrace();  
  25.        ctx.close();  
  26.     }  
  27.     @Override  
  28.     public void channelActive(final ChannelHandlerContext ctx) {  
  29.             ctx.writeAndFlush("有客户端连接"); // (3)  
  30.     }  
  31.     
  32. }    

TcpClientHander

[java]  view plain  copy
 print ?
  1. <span style="font-size:18px;">package com.bimatrix.revit.nettyTest;  
  2.   
  3. import io.netty.channel.ChannelHandlerAdapter;  
  4. import io.netty.channel.ChannelHandlerContext;  
  5.   
  6. public class TcpClientHandler extends ChannelHandlerAdapter {    
  7.     public TcpClientHandler() {    
  8.     }    
  9.     //private byte[] req;  
  10.     /**  
  11.      * 链路链接成功  
  12.      */    
  13.     @Override    
  14.     public void channelActive(ChannelHandlerContext ctx) throws Exception {    
  15.         /*for (int i = 0; i < 1000; i++) { 
  16.             ctx.writeAndFlush("1ac"); 
  17.         } */  
  18.         // 链接成功后发送    
  19.     }    
  20.     
  21.     @Override    
  22.     public void channelRead(ChannelHandlerContext ctx, Object msg)    
  23.             throws Exception {    
  24.          System.out.println("client收到数据" +msg);  
  25. //       ctx.write("收到数据!");   
  26. //       ctx.write(msg);   
  27. //       ctx.write("w2d");   
  28.     
  29.     }    
  30.     
  31.     @Override    
  32.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {    
  33.         ctx.flush();    
  34.     }    
  35.     
  36.     @Override    
  37.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)    
  38.             throws Exception {    
  39.         cause.printStackTrace();    
  40.         ctx.close();    
  41.     }    
  42. }  </span>  



TcpClient

[java]  view plain  copy
 print ?
  1. package com.bimatrix.revit.nettyTest;  
  2.   
  3. import io.netty.bootstrap.Bootstrap;    
  4. import io.netty.channel.Channel;    
  5. import io.netty.channel.ChannelInitializer;    
  6. import io.netty.channel.ChannelOption;    
  7. import io.netty.channel.ChannelPipeline;    
  8. import io.netty.channel.EventLoopGroup;    
  9. import io.netty.channel.nio.NioEventLoopGroup;    
  10. import io.netty.channel.socket.nio.NioSocketChannel;    
  11. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;    
  12. import io.netty.handler.codec.LengthFieldPrepender;    
  13. import io.netty.handler.codec.string.StringDecoder;    
  14. import io.netty.handler.codec.string.StringEncoder;    
  15. import io.netty.util.CharsetUtil;    
  16.     
  17. import org.apache.log4j.Logger;    
  18.     
  19. public class TcpClient {    
  20.     private static final Logger logger = Logger.getLogger(TcpClient.class);    
  21.     public static String HOST = "127.0.0.1";    
  22.     public static int PORT = 9999;    
  23.         
  24.     public static Bootstrap bootstrap = getBootstrap();    
  25.     public static Channel channel = getChannel(HOST,PORT);    
  26.     /**  
  27.      * 初始化Bootstrap  
  28.      * @return  
  29.      */    
  30.     public static final Bootstrap getBootstrap(){    
  31.         EventLoopGroup group = new NioEventLoopGroup();    
  32.         Bootstrap b = new Bootstrap();    
  33.         b.group(group).channel(NioSocketChannel.class);    
  34.         b.handler(new ChannelInitializer<Channel>() {    
  35.             @Override    
  36.             protected void initChannel(Channel ch) throws Exception {    
  37.                 ChannelPipeline pipeline = ch.pipeline();    
  38.                 pipeline.addLast("frameDecoder"new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0404));    
  39.                 pipeline.addLast("frameEncoder"new LengthFieldPrepender(4));    
  40.                 pipeline.addLast("decoder"new StringDecoder(CharsetUtil.UTF_8));    
  41.                 pipeline.addLast("encoder"new StringEncoder(CharsetUtil.UTF_8));    
  42.                 pipeline.addLast("handler"new TcpClientHandler());    
  43.             }    
  44.         });    
  45.         b.option(ChannelOption.SO_KEEPALIVE, true);    
  46.         return b;    
  47.     }    
  48.     
  49.     public static final Channel getChannel(String host,int port){    
  50.         Channel channel = null;    
  51.         try {    
  52.             channel = bootstrap.connect(host, port).sync().channel();    
  53.         } catch (Exception e) {    
  54.             logger.error(String.format("连接Server(IP[%s],PORT[%s])失败", host,port),e);    
  55.             return null;    
  56.         }    
  57.         return channel;    
  58.     }    
  59.     
  60.     public static void sendMsg(String msg) throws Exception {    
  61.         if(channel!=null){    
  62.             channel.writeAndFlush(msg).sync();    
  63.         }else{    
  64.             logger.warn("消息发送失败,连接尚未建立!");    
  65.         }    
  66.     }    
  67.     
  68.     public static void main(String[] args) throws Exception {  
  69.    
  70.         try {    
  71.             long t0 = System.nanoTime();    
  72.             for (int i = 0; i < 100000; i++) {   
  73.                 if(i%3==0){  
  74.                      TcpClient.sendMsg(i+"11aaa222aaa");   
  75.                 }else if(i%3==1){  
  76.                      TcpClient.sendMsg(i+"222cccdddbbbbbbbbbbbb");   
  77.                 }else if(i%3==2){  
  78.                  TcpClient.sendMsg(i+"333cccddda12ccccccccccccccccccccccccc");   
  79.                 }  
  80.             }    
  81.             long t1 = System.nanoTime();    
  82.             System.out.println((t1-t0)/1000000.0);    
  83.         } catch (Exception e) {    
  84.             e.printStackTrace();    
  85.         }    
  86.     }    
  87. }    


上面代码部分下面这一块 主要测试消息发送是否会造成粘包
 for (int i = 0; i < 100000; i++) { 
             if(i%3==0){
             TcpClient.sendMsg(i+"11aaa222aaa"); 
             }else if(i%3==1){
             TcpClient.sendMsg(i+"222cccdddbbbbbbbbbbbb"); 
             }else if(i%3==2){
            TcpClient.sendMsg(i+"333cccddda12ccccccccccccccccccccccccc"); 
             }
            }  
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
       在Java界,Netty无疑是开发网络应用的拿手菜。你不需要太多关注复杂的NIO模型和底层网络的细节,使用其丰富的接口,可以很容易的实现复杂的通讯功能。 本课程准备的十二个实例,按照由简单到复杂的学习路线,让你能够快速学习如何利用Netty来开发网络通信应用。                每个实例简洁、清爽、实用,重点在“用”上,即培训大家如何熟练的使用Netty解决实际问题,抛弃以往边讲应用边分析源码的培训模式所带来的“高不成低不就”情况,在已经能够熟练使用、并且清楚开发流程的基础上再去分析源码就会思路清晰、事半功倍。        本套课程的十二个实例,各自独立,同时又层层递进,每个实例都是针对典型的实际应用场景,学了马上就能应用到实际项目中去。 学习好Netty 总有一个理由给你惊喜!! 一、应用场景        Netty已经众多领域得到大规模应用,这些领域包括:物联网领域、互联网领域、电信领域、大数据领域、游戏行业、企业应用、银行证券金融领域、。。。  二、技术深度        多款开源框架中应用了Netty,如阿里分布式服务框架 Dubbo 的 RPC 框架、淘宝的消息中间件 R0cketMQ、Hadoop 的高性能通信和序列化组件 Avro 的 RPC 框架、开源集群运算框架 Spark、分布式计算框架 Storm、并发应用和分布式应用 Akka、。。。  三、就业前景         很多大厂在招聘高级/资深Java工程师时要求熟练学习、或熟悉Netty,下面只是简要列出,这个名单可以很长。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值