socket 和mina 的区别

Android Socket使用详解 即套接字,是一个对 TCP / IP协议进行封装 的编程调用接口(API)即通过Socket,我们才能在Andorid平台上通过TCP/IP协议进行开发Socket不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)成对出现,一对套接字:Socket ={(IP地址1:PORT端口号),(IP地址2:PORT端口号)} 阅读详情

通过优锐课核心java学习笔记中,我们可以看到socket 和mina 的区别,码了很多专业的相关知识, 分享给大家参考学习。

MINA,Grizzly[grizzly-nio-framework],xSocket都是基于 java nio的 server framework.
  这里的性能缺陷的焦点是指当一条channel上的SelectionKey.OP_READ ready时,1.是由select thread读完数据之后再分发给应用程序的handler,2.还是直接就分发,由handler thread来负责读数据和handle.
  mina,xsocket是1. grizzly-nio-framework是2.
  尽管读channel buffer中bytes是很快的,但是如果我们放大,当连接channel达到上万数量级,甚至更多,这种延迟响应的效果将会愈加明显.
  MINA:
  for all selectedKeys
  {
  read data then fireMessageReceived.
  }
  xSocket:
  for all selectedKeys
  {
  read data ,append it to readQueue then performOnData.
  }
  其中mina在fireMessageReceived时没有使用threadpool来分发,所以需要应用程序在handler.messageReceived中再分发.而xsocket的performOnData默认是分发给threadpool[WorkerPool],WorkerPool虽然解决了线程池中的线程不能充到最大的问题[跟tomcat6的做法一样],但是它的调度机制依然缺乏灵活性.
  Grizzly:
  for all selectedKeys
  {
  [NIOContext—filterChain.execute—>our filter.execute]<------run In DefaultThreadPool
  }
  grizzly的DefaultThreadPool几乎重写了java util concurrent threadpool,并使用自己的LinkedTransferQueue,但同样缺乏灵活的池中线程的调度机制.
  
  下面分别是MINA,xSocket,Grizzly的源码分析:
  Apache MINA (mina-2.0.0-M6源码为例):
  我们使用mina nio tcp最常用的样例如下:
  NioSocketAcceptor acceptor = new NioSocketAcceptor(/NioProcessorPool’s size/);
  DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
  
  //chain.addLast(“codec”, new ProtocolCodecFilter(
  //new TextLineCodecFactory()));
  …
  // Bind
  acceptor.setHandler(/our IoHandler/);
  acceptor.bind(new InetSocketAddress(port));
  ------------------------------------------------------------------------------------
  首先从NioSocketAcceptor(extends AbstractPollingIoAcceptor)开始,
  bind(SocketAddress)—>bindInternal—>startupAcceptor:启动AbstractPollingIoAcceptor.Acceptor.run使用executor[Executor]的线程,注册[interestOps:SelectionKey.OP_ACCEPT],然后wakeup selector.
  一旦有连接进来就构建NioSocketSession–对应–channal,然后session.getProcessor().add(session)将当前的channal加入到NioProcessor的selector中去[interestOps:SelectionKey.OP_READ],这样每个连接中有请求过来就由相应的NioProcessor来处理.
  这里有几点要说明的是:
  1.一个NioSocketAcceptor对应了多个NioProcessor,比如NioSocketAcceptor就使用了SimpleIoProcessorPool DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1.当然这个size在new NioSocketAcceptor的时候可以设定.
  2.一个NioSocketAcceptor对应一个java nio selector[OP_ACCEPT],一个NioProcessor也对应一个java nio selector[OP_READ].
  3.一个NioSocketAcceptor对应一个内部的AbstractPollingIoAcceptor.Acceptor—thread.
  4.一个NioProcessor也对应一个内部的AbstractPollingIoProcessor.Processor—thread.
  5.在new NioSocketAcceptor的时候如果你不提供Executor(线程池)的话,那么默认使用Executors.newCachedThreadPool().
  这个Executor将被NioSocketAcceptor和NioProcessor公用,也就是说上面的Acceptor—thread(一条)和Processor—thread(多条)都是源于这个Executor.
  当一个连接java nio channal–NioSession被加到ProcessorPool[i]–NioProcessor中去后就转入了AbstractPollingIoProcessor.Processor.run,
  AbstractPollingIoProcessor.Processor.run方法是运行在上面的Executor中的一条线程中的,当前的NioProcessor将处理注册在它的selector上的所有连接的请求[interestOps:SelectionKey.OP_READ].
  AbstractPollingIoProcessor.Processor.run的主要执行流程:
  for (;😉 {
  …
  int selected = selector(final SELECT_TIMEOUT = 1000L);
  …
  if (selected > 0) {
  process();
  }
  …
  }
  process()–>for all session-channal:OP_READ -->read(session):这个read方法是AbstractPollingIoProcessor.private void read(T session)方法.
  read(session)的主要执行流程是read channal-data to buf,if readBytes>0 then IoFilterChain.fireMessageReceived(buf)/我们的IoHandler.messageReceived将在其中被调用/;
  到此mina Nio 处理请求的流程已经明了.
  mina处理请求的线程模型也出来了,性能问题也来了,那就是在AbstractPollingIoProcessor.Processor.run–>process–>read(per session)中,在process的时候mina是for all selected-channals 逐次read data再fireMessageReceived到我们的IoHandler.messageReceived中,而不是并发处理,这样一来很明显后来的请求将被延迟处理.
  我们假设:如果NioProcessorPool’s size=2 现在有200个客户端同时连接过来,假设每个NioProcessor都注册了100个连接,对于每个NioProcessor将依次顺序处理这100个请求,那么这其中的第100个请求要得到处理,那它只有等到前面的99个被处理完了.
  有人提出了改进方案,那就是在我们自己的IoHandler.messageReceived中利用线程池再进行分发dispatching,这个当然是个好主意.
  但是请求还是被延迟处理了,因为还有read data所消耗的时间,这样第100个请求它的数据要被读,就要等前面的99个都被读完才行,即便是增加ProcessorPool的尺寸也不能解决这个问题.
  此外mina的陷阱(这个词较时髦)也出来了,就是在read(session)中,在说这个陷阱之前先说明一下,我们的client端向server端发送一个消息体的时候不一定是完整的只发送一次,可能分多次发送,特别是在client端忙或要发送的消息体的长度较长的时候.而mina在这种情况下就会call我们的IoHandler.messageReceived多次,结果就是消息体被分割了若干份,等于我们在IoHandler.messageReceived中每次处理的数据都是不完整的,这会导致数据丢失,无效.
  下面是read(session)的源码:
  private void read(T session) {
  IoSessionConfig config = session.getConfig();
  IoBuffer buf = IoBuffer.allocate(config.getReadBufferSize());
  final boolean hasFragmentation =
  session.getTransportMetadata().hasFragmentation();
  try {
  int readBytes = 0;
  int ret;
  try {
  if (hasFragmentation/hasFragmentation一定为ture,也许mina的开发人员也意识到了传输数据的碎片问题,但是靠下面的处理是远远不够的,因为client一旦间隔发送,ret就可能为0,退出while,不完整的readBytes将被fire/) {
  while ((ret = read(session, buf)) > 0) {
  readBytes += ret;
  if (!buf.hasRemaining()) {
  break;
  }
  }
  } else {
  ret = read(session, buf);
  if (ret > 0) {
  readBytes = ret;
  }
  }
  } finally {
  buf.flip();
  }
  if (readBytes > 0) {
  IoFilterChain filterChain = session.getFilterChain();
  filterChain.fireMessageReceived(buf);
  buf = null;
  if (hasFragmentation) {
  if (readBytes << 1 < config.getReadBufferSize()) {
  session.decreaseReadBufferSize();
  } else if (readBytes == config.getReadBufferSize()) {
  session.increaseReadBufferSize();
  }
  }
  }
  if (ret < 0) {
  scheduleRemove(session);
  }
  } catch (Throwable e) {
  if (e instanceof IOException) {
  scheduleRemove(session);
  }
  IoFilterChain filterChain = session.getFilterChain();
  filterChain.fireExceptionCaught(e);
  }
  }
  这个陷阱大家可以测试一下,看会不会一个完整的消息被多次发送,你的IoHandler.messageReceived有没有被多次调用.
  要保持我们应用程序消息体的完整性也很简单只需创建一个断点breakpoint,然后set it to the current IoSession,一旦消息体数据完整就dispatching it and remove it from the current session.
  --------------------------------------------------------------------------------------------------
  下面以xSocket v2_8_8源码为例:
  tcp usage e.g:
  IServer srv = new Server(8090, new EchoHandler());
  srv.start() or run();
  -----------------------------------------------------------------------
  class EchoHandler implements IDataHandler {
  public boolean onData(INonBlockingConnection nbc)
  throws IOException,
  BufferUnderflowException,
  MaxReadSizeExceededException {
  String data = nbc.readStringByDelimiter("/r/n");
  nbc.write(data + “/r/n”);
  return true;
  }
  }
  ------------------------------------------------------------------------
  说明1.Server:Acceptor:IDataHandler ------1:1:1
  Server.run–>IoAcceptor.accept()在port上阻塞,一旦有channel就从IoSocketDispatcherPool中获取一个IoSocketDispatcher,同时构建一个IoSocketHandler和NonBlockingConnection,调用
  Server.LifeCycleHandler.onConnectionAccepted(ioHandler) initialize the IoSocketHandler.注意:IoSocketDispatcherPool.size默认为2,也就是说只有2条do select的线程和相应的2个IoSocketDispatcher.这个和MINA的NioProcessor数是一样的.
  说明2.IoSocketDispatcher[java nio Selector]:IoSocketHandler:NonBlockingConnection------1:1:1
  在IoSocketDispatcher[对应一个Selector].run中—>IoSocketDispatcher.handleReadWriteKeys:
  for all selectedKeys
  {
  IoSocketHandler.onReadableEvent/onWriteableEvent.
  }
  IoSocketHandler.onReadableEvent的处理过程如下:
  1.readSocket();
  2.NonBlockingConnection.IoHandlerCallback.onData
  NonBlockingConnection.onData—>appendDataToReadBuffer: readQueue append data
  3.NonBlockingConnection.IoHandlerCallback.onPostData
  NonBlockingConnection.onPostData—>HandlerAdapter.onData[our dataHandler] performOnData in WorkerPool[threadpool].
  
  因为是把channel中的数据读到readQueue中,应用程序的dataHandler.onData会被多次调用直到readQueue中的数据读完为止.所以依然存在类似mina的陷阱.解决的方法依然类似,因为这里有NonBlockingConnection.
  ----------------------------------------------------------------------------------------------
  再下面以grizzly-nio-framework v1.9.18源码为例:
  tcp usage e.g:
  Controller sel = new Controller();
  sel.setProtocolChainInstanceHandler(new DefaultProtocolChainInstanceHandler(){
  public ProtocolChain poll() {
  ProtocolChain protocolChain = protocolChains.poll();
  if (protocolChain == null){
  protocolChain = new DefaultProtocolChain();
  //protocolChain.addFilter(our app’s filter/应用程序的处理从filter开始,类似mina.ioHandler,xSocket.dataHandler/);
  //protocolChain.addFilter(new ReadFilter());
  }
  return protocolChain;
  }
  });
  //如果你不增加自己的SelectorHandler,Controller就默认使用TCPSelectorHandler port:18888
  sel.addSelectorHandler(our app’s selectorHandler on special port);
  sel.start();
  ------------------------------------------------------------------------------------------------------------
  说明1.Controller:ProtocolChain:Filter------1:1:n,
  Controller:SelectorHandler------1:n,SelectorHandler[对应一个Selector]:SelectorHandlerRunner------1:1,
  Controller. start()—>for per SelectorHandler start SelectorHandlerRunner to run.
  SelectorHandlerRunner.run()—>selectorHandler.select() then handleSelectedKeys:
  for all selectedKeys
  {
  NIOContext.execute:dispatching to threadpool for ProtocolChain.execute—>our filter.execute.
  }
  
  你会发现这里没有read data from channel的动作,因为这将由你的filter来完成.所以自然没有mina,xsocket它们的陷阱问题,分发提前了.但是你要注意SelectorHandler:Selector:SelectorHandlerRunner:Thread[SelectorHandlerRunner.run]都是1:1:1:1,也就是说只有一条线程在doSelect then handleSelectedKeys.
  相比之下虽然grizzly在并发性能上更优,但是在易用性方面却不如mina,xsocket,比如类似mina,xsocket中表示当前连接或会话的IoSession,INonBlockingConnection对象在grizzly中由NIOContext来负责,但是NIOContext并没有提供session/connection lifecycle event,以及常规的read/write操作,这些都需要你自己去扩展SelectorHandler和ProtocolFilter,从另一个方面也可以说明grizzly的可扩展性,灵活性更胜一筹.

喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
如果你对java技术很感兴趣也可以加入我的java学习群 V–(ddmsiqi)来交流学习,里面都是同行,验证【优快云2】有资源共享。
不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代

Mina网络编程实例:构建高效的Socket应用 Mina(Apache MINA)是一个高性能、可扩展的Java网络应用框架,它提供了简单而强大的API,用于构建基于Socket的网络应用程序。本文将介绍如何使用Mina框架来编写高效的Socket网络应用,并提供相应的示例代码。现在,我们将创建一个简单的Mina客户端应用程序,用于与服务器端进行通信。接下来,我们将创建一个简单的Mina服务器端应用程序。首先,我们需要在项目中引入Mina的相关依赖。)来处理收发的消息。在上述示例中,我们创建了一个。在上述示例中,我们创建了一个。实例,并设置了处理器( 阅读详情

相关推荐

Socket及Mina的讲解

androidpn项目基础,socket和mina,详情见博客http://blog.youkuaiyun.com/specialshoot/article/details/50678374

朝花夕拾之socket的基本使用以及mina框架简单介绍

工欲善其事,必先利其器,从互联网诞生到现在,基本上所有的程序都是网络程序,很少有单机版的程序了。 而网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机。我们现在进行网络编程,基本上都是使用已经封装好的框架,毕竟自己实现维护一套网络编程框架,费时费力不说,做出来之后还不一定好用,有那时间多保养保养头发。 Socket简介 记得大学学习java的时候,并没有接触网络编程相...

weixin_34198762的博客 365

mina框架中socket使用,有服务端和客户端。

mina框架中socket使用,有服务端和客户端。这是比较完整的项目。希望能给后人点参考

socket通讯mina框架学习与熟悉

1.MINA MINA 是一个专门设计既能工作在客户端又能工作在服务器端的网络框架 1.1 架构图 1.1.1 应用程序架构 MINA处于应用程序和基础网络层之间作为粘合剂(可以基于TCP、UDP、in-VM 通信或是客户端的RS-232C串行协议),只用在mina上设计自己的应用实现,不需要去处理网络层的复杂业务 (底层是基于JAVA的NIO 1.0实现的) 1.1.2 核心部分架构 内部可以分为3个层次: I/O Service - 执行实际的I / O,创建一个I/O Service: 可以选择

fggsgnhz的博客 620

一般Socket客户端与Mina NIO Socket客户端对比示例

NULL 博文链接:https://ginge.iteye.com/blog/363178

海康WEB3.3控件开发包 V3.3 前端vue项目调用实时监控画面

本需求的完成离不开后端将设备映射到公网, 以及前端单独部署demo页面这个思路的转变。

hero8011的博客 1万+

mina第三方类替代socket实现tcp通讯

socket是java tcp通讯的封装工具,有时在工业上使用,配置需要的开发水平较高,偶尔不慎,就造成短路,接收不到数据。处理业务的实现类 ,相当于 service的实现类,处理具体的业务,也相当于一个线程。log.info("9001收到二维码 入库开始 === ");log.error("9001没扫描到二维码,过===");log.info("2线收到二维码 9001:" + mes);log.info("9008 收到 ====" + mes);log.info("判定为包头:" + mes);

somdip的博客 650

飞行器坐标转换

本文定义的是右手直角坐标系,x−y−zx-y-zx−y−z轴分别为北-天-东。从AAA坐标系到BBB坐标系是分别绕y−z−xy-z-xy−z−x轴,即天-东-北旋转ψ−θ−γψ−θ−γ。如果AAA是惯性系,BBB是机体系,则这三个角度分别为偏航角、俯仰角、横滚角。图1 惯性系到机体系。

gongfuyd的博客 1355

socket 通信的解决方案-Mina框架的使用心得及相关要点

https://blog.youkuaiyun.com/wuliusir/article/details/51206654 前言 笔者之前的工作主要是做 java 的 web 端开发,后因工作原因参与了一个国家级的大项目,主要负责其中底层通讯的前置机模块。几经波折,将该系统完成后,结果在第一轮的测试中就惨败退回。其根本原因就在于原设计文档的要求单“通信机”与“终端”( 注一 )之间的并发量要达到 2W 以上的...

MOTOLT的博客 413

机械设计师必看:如何用Autodesk Inventor高效完成钣金设计(附实战案例)

本文为机械设计师详细解析了如何利用Autodesk Inventor Professional高效完成钣金设计。文章通过一个钣金防护罩的实战案例,系统介绍了从核心设计逻辑、建模流程、参数化技巧到工程图输出的完整工作流,旨在帮助设计师掌握智能化的设计方法,显著提升从概念到制造的设计效率与准确性。

honey的博客 1181

Sigrity IBIS建模实战:如何用T2B工具快速转换SPICE模型(附避坑指南)

本文详细介绍了如何使用Sigrity T2B工具将SPICE模型高效转换为IBIS模型,涵盖从环境配置、模型预处理到转换流程和验证策略的全过程。通过实战案例和避坑指南,帮助硬件工程师掌握高速电路设计中的IBIS建模技术,提升信号完整性分析效率。

weixin_29243279的博客 395

nio socket 及其开源框架MINA学习总结

最近花了点时间研究了一下nio,及其开源框架MINA,现把心得总结如下:1:传统socket:阻塞式通信每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。这种方式具有很高的响应速度,并且控制起来也很简单,在连接数较少的时候非常有效,但是如果对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。ex

elimago的专栏 5093

遇到问题--OpenClaw--API rate limit reached. Please try again later429 您的账户已达到速率限制,请您控制请求频率

OpenClaw调用glm-4.7-flash模型时触发智谱AI平台429速率限制错误。分析发现当前重试策略采用固定间隔(7-11秒)导致连续失败,且未记录关键响应头信息。解决方案分三步:1)开启响应头日志获取配额详情;2)将重试策略改为带抖动的指数退避(初始1秒,最大60秒);3)在网关层实现令牌桶限流主动控制请求频率。需特别注意令牌配额(TPM)可能比请求次数(RPM)更早触达限制。

直到世界的尽头 2616

socket, nio socket 及nio socket框架MINA总结

原文地址:http://blog.youkuaiyun.com/lcllcl987/article/details/1566114 nio学习: 最近花了点时间研究了一下nio,及其开源框架MINA,现把心得总结如下: 1:传统socket:阻塞式通信 每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。 这种方式具有很高的响应速度,并且控制起来也

fgsgsgfgsg的专栏 348

大模型——dify实战通过dify搭建你自己的图片识别服务

本文介绍了如何通过Dify平台搭建图片识别服务。首先创建工作流,添加支持图片上传的字段,并配置视觉模型qwen-vl-max-latest进行图像分析。文章详细说明了各步骤操作,包括字段设置、模型选择、提示词编写等。在测试阶段发现URL解析问题后,提供了解决方案:修改Dify的.env文件,调整FILES_URL配置并重启服务。最终成功实现上传图片或输入图片链接后,AI能够准确分析并返回简洁的图片内容描述。这一方案适用于需要快速部署图像识别功能的场景。

1925

W5500以太网&PoE扩展模块原理图设计,已量产

本文将以 W5500 以太网 & PoE 扩展板为对象,从嵌入式硬件设计的视角,深度拆解其电路架构、核心器件选型、关键功能实现,以及这款板子解决行业痛点的设计思路。

不脱发的程序猿 940

mina分析

http://bhdweb.iteye.com/blog/1479459 Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议(如TCP/IP,UDP/IP协议等)下快速高效开发。

tianxiagongzheng的专栏 798

[QMT量化交易小白入门]-十二、QMT回测龙头打首板和连板的策略

class a():passA = a() #创建空的类的实例 用来保存委托状态field_list定义了需要的市场数据字段,而类a用于保存交易状态。

木头大左的博客 4757

nio socket 及其开源框架MINA学习总结(一)

nio socket 及其开源框架MINA学习总结(一) 关键字:   nio socket MINA     最近花了点时间研究了一下nio,及其开源框架MINA,现把心得总结如下: 1:传统socket:阻塞式通信 每建立一个Socke

jackfor001的专栏 1571

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

深入理解Apache Mina (6)---- Java Nio ByteBuffer与Mina ByteBuffer的区别

为了对后续关于Mina 的 ProtocolFilter( 编解码器 ) 的编写有一个更好的理解,本文讲述一下关于 Mina ByteBuffer 和 Java Nio ByteBuffer 的区别。关于 Java Nio ByteBuffer 和 Mina ByteBuffer 及其子类的类图在附件中都已经给出了。因为 Mina 的 ByteBuffer 在 Mina 2.0 以上的版本中都改称

chengzhezhijian的专栏 725

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Java传统Socket实例——TimeServer

该实例是基于传统的ServerSocket和Socket来写的,因此使用的是也是传统的BIO(Blocking IO),并发的时候都是通过阻塞的方式来处理的,该实例是和MINA 2.0实例——TimeServer对应的,采用单线程通过循环来提供并发访问,以更好的反应BIO和NIO的区别,代码如下: import java.io.DataInputStream; import java.io.

2799

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Mina框架的使用

什么是Mina框架 Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件驱动的、异步的API。是用来代替 NIO网络框架的,对NIO框架进行了一层封装的Socket库。 Mina主页 下载地址 为什么使用Mina? 传统socket:阻塞式通...

weixin_33725126的博客 388

服务器_网络通信(TCP/IP网络模型,HTTP(URL),Socket,WebSocket,BIO,NIO,AIO,Mina框架,Netty框架)

通信协议 客户端和服务器之间通信所需要遵循的某种规则 网络模型OSI(Open System Interconnnection) 该模型把把网络通信分为7层(物理层,数据链路层,网络层,传输层,会话层,表示层,应用层),是设计和描述计算机网络通信的基本架构。 在实际应用中一般只是用到4层。 TCP/IP网络模型 这个模型是一系列网络协议的总层,是互联网的基础。 4个层次 链接层 对应的...

binge_kong的博客 1630
上一篇: 面试题解答系列:在 Spring中如何注入java集合
下一篇: 面试题解答系列:算法连载之求解两个有序数组的中位数
程序员plus
博客等级 码龄8年 41粉丝 151原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值