服务器IO处理模型

阻塞IO服务器模型之单线程服务器模型 单线程服务器模型是最简单的一个服务器模型,几乎我们所有程序员在刚开始接触网络编程(不管是B/S结构还是C/S结构)都是从这个简单的模型开始。这种模型只提供同时一个客户端访问,多个客户端访问必须要等到前一个客户端访问结束,一个一个排队,即提供一问一答服务。 图2-6-1-1 单线程阻塞服务器模型       图2-6-1-1展示了单线程阻塞服务器是怎样响应客户端的访问。首先,服务器必须 阅读详情

背景

本文探讨的服务器模型主要指的是服务端对IO的处理模型。从不同的维度可以有不同的分类,本文主要从IO的阻塞与非阻塞,IO处理的单线程和多线程角度探讨服务器模型。
下面将对线程和阻塞的组合进行分析。

  • 对于IO,可以分成阻塞IO和非阻塞IO两大类型。阻塞IO在做IO读写操作时会使当前线程进入阻塞状态,而非阻塞IO则不会进入阻塞状态。
  • 对于线程,单线程情况下由一条线程负责所有客户端连接的IO操作,而多线程情况下则由若干线程共同处理所有客户端连接的IO操作。

单线程阻塞IO模型

单线程阻塞IO是最简单的一种服务器模型,几乎所有程序员刚开始接触时都从这个简单的模型开始。这种模型只能同时处理一个客户端访问,并且在IO操作上是阻塞的,线程会一直在等待,而不会做其他事情。对于多个客户端访问,必须要等到前一个客户端访问结束才能进行下一个访问的处理,请求一个一个排队,只提供一问一答服务。

这种模型的特点是服务器系统资源消耗较小,但并发能力低,容错能力差。
单线程阻塞IO模型

多线程阻塞IO模型

针对单线程阻塞IO模型的缺点,我们可以使用多线程对其进行改进,使之能并发地对多个客户端同时进行响应。多线程模型的核心就是利用多线程机制为每个客户端分配一个线程。

这种模型的IO操作也是阻塞的,因为每个线程执行到读取或写入操作时都将进入阻塞状态,直到读取客户端的数据或数据写入客户端后才解除阻塞状态。尽管IO操作阻塞,但这种模式比单线程处理的性能明显高了,它不用等到第一个请求处理完才处理第二个,而是并发地处理客户端请求,客户端连接与服务端处理线程的比例是1:1。

多线程阻塞IO模型的特点是支持多个客户端并发响应,处理能力得到大幅提高,有较大的并发量,但服务器系统资源消耗量较大,而且多线程之间会产生线程切换成本,同时拥有较复杂的结构。
多线程阻塞IO模型

单线程非阻塞IO模型

多线程阻塞IO模型通过引入多线程确实提高了服务器端的并发处理能力,但每个连接都需要一个线程负责IO操作。当连接数量较多时可能导致机器线程数量太多,而这些线程大多数时间却处于等待状态,造成极大的资源浪费。鉴于多线程阻塞IO模型的特点,有没有可能用一个线程就可以维护多个客户端连接并且不会阻塞在读写操作呢?下面介绍单线程非阻塞IO模型。

单线程非阻塞IO模型最重要的一个特点是,在调用读取或写入接口后立即返回,而不会进入阻塞状态。在探讨单线程非阻塞IO模型前必须要先了解非阻塞情况下套接字事件的检测机制,因为对于单线程非阻塞模型最重要的事情是检测哪些连接有感兴趣的事件发生。一般会有以下三种检测方式。

应用程序遍历套接字的事件检测

当多个客户端向服务器请求时,服务器端会将每个连接保存在一个套接字连接列表中,应用层线程对套接字列表轮询尝试读取或写入。对于读取操作,如果成功读取到若干数据,则对读取到的数据进行处理;如果读取失败,则下一个循环再继续尝试。对于写入操作,先尝试将数据写入指定的某个套接字,写入失败则下一个循环再继续尝试。

这样看来,不管有多少个套接字连接,它们都可以被一个线程管理,一个线程负责遍历这些套接字列表,不断地尝试读取或写入数据。这很好地利用了阻塞的时间,处理能力得到提升。但这种模型需要在应用程序中遍历所有的套接字列表,同时需要处理数据的拼接,连接空闲时可能也会占用较多CPU资源,不适合实际使用。对此改进的方法是使用事件驱动的非阻塞方式。
非阻塞遍历套接字

内核遍历套接字的事件检测

这种方式将套接字的遍历工作交给了操作系统内核,把对套接字遍历的结果组织成一系列的事件列表并返回应用层处理。对于应用层,它们需要处理的对象就是这些事件,这就是其中一种事件驱动的非阻塞方式的实现。

服务器端有多个客户端连接,应用层向内核请求读写事件列表。内核遍历所有套接字并生成对应的可读列表readList和可写列表writeList。readList标明了每个套接字是否可读,例如socket1的值为1,表示可读,socket2的值为0,表示不可读。writeList则标明了每个套接字是否可写。应用层遍历读写事件列表readList和writeList,做相应的读写操作。

内核遍历套接字时已经不用在应用层对所有套接字进行遍历,将遍历工作下移到内核层,这种方式有助于提高检测效率。然而,它需要将所有连接的可读事件列表和可写事件列表传到应用层,假如套接字连接数量变大,列表从内核复制到应用层也是不小的开销。另外,当活跃连接较少时,内核与应用层之间存在很多无效的数据副本,因为它将活跃和不活跃的连接状态都复制到应用层中。
内核遍历套接字的事件检测

内核基于回调的事件检测

通过遍历的方式检测套接字是否可读可写是一种效率比较低的方式,不管是在应用层中遍历还是在内核中遍历。所以需要另外一种机制来优化遍历的方式,那就是回调函数。内核中的套接字都对应一个回调函数,当客户端往套接字发送数据时,内核从网卡接收数据后就会调用回调函数,在回调函数中维护事件列表,应用层获取此事件列表即可得到所有感兴趣的事件。
内核基于回调的事件检测方式有两种。

内核基于回调的事件检测方式一

第一种是用可读列表readList和可写列表writeList标记读写事件,套接字的数量与readList和writeList两个列表的长度一样,readList第一个元素标为1则表示套接字1可读,同理,writeList第二个元素标为1则表示套接字2可写。如图所示,多个客户端连接服务器端,当客户端发送数据过来时,内核从网卡复制数据成功后调用回调函数将readList第一个元素置为1,应用层发送请求读、写事件列表,返回内核包含了事件标识的readList和writeList事件列表,进而分表遍历读事件列表readList和写事件列表writeList,对置为1的元素对应的套接字进行读或写操作。这样就避免了遍历套接字的操作,但仍然有大量无用的数据(状态为0的元素)从内核复制到应用层中。于是就有了第二种事件检测方式。
内核基于回调的事件检测方式一

内核基于回调的事件检测方式二

内核基于回调的事件检测方式二如图所示。服务器端有多个客户端套接字连接。首先,应用层告诉内核每个套接字感兴趣的事件。接着,当客户端发送数据过来时,对应会有一个回调函数,内核从网卡复制数据成功后即调回调函数将套接字1作为可读事件event1加入到事件列表。同样地,内核发现网卡可写时就将套接字2作为可写事件event2添加到事件列表中。最后,应用层向内核请求读、写事件列表,内核将包含了event1和event2的事件列表返回应用层,应用层通过遍历事件列表得知套接字1有数据待读取,于是进行读操作,而套接字2则可以写入数据。
内核基于回调的事件检测方式二
上面两种方式由操作系统内核维护客户端的所有连接并通过回调函数不断更新事件列表,而应用层线程只要遍历这些事件列表即可知道可读取或可写入的连接,进而对这些连接进行读写操作,极大提高了检测效率,自然处理能力也更强。

对于Java来说,非阻塞I/O的实现完全是基于操作系统内核的非阻塞I/O,它将操作系统的非阻塞I/O的差异屏蔽并提供统一的API,让我们不必关心操作系统。JDK会帮我们选择非阻塞I/O的实现方式,例如对于Linux系统,在支持epoll的情况下JDK会优先选择用epoll实现Java的非阻塞I/O。这种非阻塞方式的事件检测机制就是效率最高的“内核基于回调的事件检测”中的第二种方式。

在了解了非阻塞模式下的事件检测方式后,重新回到对单线程非阻塞I/O模型的讨论。虽然只有一个线程,但是它通过把非阻塞读写操作与上面几种检测机制配合就可以实现对多个连接的及时处理,而不会因为某个连接的阻塞操作导致其他连接无法处理。在客户端连接大多数都保持活跃的情况下,这个线程会一直循环处理这些连接,它很好地利用了阻塞的时间,大大提高了这个线程的执行效率。

单线程非阻塞I/O模型的主要优势体现在对多个连接的管理,一般在同时需要处理多个连接的发场景中会使用非阻塞NIO模式,此模型下只通过一个线程去维护和处理连接,这样大大提高了机器的效率。一般服务器端才会使用NIO模式,而对于客户端,出于方便及习惯,可使用阻塞模式的套接字进行通信。

参考资料:Tomcat内核设计剖析

扫码器USB键盘报告描述符数据格式解析 Byte0用于判断Shift是否按下,当按下时Byte0的Bit1会置1,即0x02,若未按下,Bit为0,即0x00。0x00 0x00 0x00 0x00 0x00 0x00 0x00--->>未按下Shift。0x00 0x00 0x00 0x00 0x00 0x00 0x00--->>按下Shift。0x00 0x04 0x00 0x00 0x00 0x00 0x00--->>输出A。0x00 0x04 0x00 0x00 0x00 0x00 0x00--->>输出a。 阅读详情

相关推荐

ROS应用之如何配置RTOS满足机器人系统中的实时要求

实时操作系统(RTOS)基本概念实时操作系统(RTOS)是设计用于实时应用的操作系统,其主要目标是在确定的时间内完成任务。RTOS的任务调度算法和优先级控制机制能够确保高优先级任务按时完成。精确的传感器数据采集:传感器数据需要在规定时间内采集并传输给控制系统。快速响应外部事件:对于控制系统,需要确保指令在最短的时间内得到响应。任务的调度周期:任务的周期可以通过公式计算,其中 ftask 是任务的调度频率。优先级分配。

weixin_68094467的博客 1008

【IO与服务器】

在 Linux 的 缓存 IO 机制中,操作系统会将 IO 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。这给网络编程带来了一个很大的问题,如在调用send()的同时,进程将被阻塞,在此期间,进程将无法执行任何运算或响应任何的网络请求。整个IO请求的过程中,虽然用户线程每次发起IO请求后可以立即返回,但是为了等到数据,仍需要不断地轮询、重复请求,消耗了大量的CPU的资源。...

Ccccspring的博客 1197

Matlab图像处理频域滤波实现——高斯低通、高通、带通带阻滤波器

如果你想要进一步了解更多的相关知识,

小嘤熊的博客 1万+

几种服务器端IO模型的简单介绍及实现

一些概念: 同步和异步 同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪,而异步是指用户进程触发I/O操作以后便开始做自己的事情,而当I/O操作已经完成的时候会得到I/O完成的通知。 阻塞和非阻塞 阻塞和非阻塞是针对于进程在访问数据的时候,根据I/O操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式...

weixin_33909059的博客 344

手把手教你用SNAP做全极化SAR图像分类

引言 最近在研究极化SAR图像分类方面的内容,发现用SNAP软件可以很方便的实现图像的分类。因为在入门过程中踩了很多坑,浪费了一些时间,为了不让大家踩坑,所以决定写下这篇教程。 前期准备 软件下载 SNAP是欧空局旗下的一个SAR图像处理软件,可以点击下载地址进行下载。 数据下载 数据下载地址:https://mdacorporation.com/sample_data/RS2_OK76385_...

zz651044657的博客 1万+

MOOS-ivp 实验三 MOOS简介(1)

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录系列文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例

weixin_44151170的博客 7434

Linux 性能分析之 IO 篇

这个值越大,说明产生的 IO 请求较多,IO 压力较大,我们可以结合 %idle 参数来看,如果 %idle < 70% 就说明 IO 比较繁忙了。rrqm/s 和 wrqm/s:分别每秒进行合并的读操作数和写操作数,这是什么意思呢,合并就是说把多次 IO 请求合并成少量的几次,这样可以减小 IO 开销,buffer 存在的意义就是为了解决这个问题的。一般这几个值偏大,都意味着系统 IO 的消耗较大,对于读请求较大的服务器,b、bo、wa 的值偏大,而写请求较大的服务器,b、bi、wa 的值偏大。

tecoes的博客 4022

保姆级教程:用Python+Mediapipe实时捕捉手势,驱动Unity虚拟手模型(附完整源码)

本文详细介绍了如何利用Python的Mediapipe库和Unity实现实时手势识别与虚拟手模型驱动。通过OpenCV进行图像采集,Mediapipe提供21个手部关键点识别,结合UDP通信协议实现Python与Unity之间的低延迟数据传输。教程包含完整源码、环境配置、核心代码实现及性能优化技巧,适用于VR教育、游戏开发等需要自然交互的场景。

weixin_42531779的博客 361

MUDUO-概述

典型的一次IO的两个阶段是什么?数据准备 和 数据读写数据准备:根据系统IO操作的就绪状态阻塞非阻塞数据读写:根据应用程序和内核的交互方式同步异步一个典型的网络IO接口调用,分为两个阶段,分别是“数据就绪”和“数据读写”,数据就绪阶段分为和,表现得结果就是,阻塞当前线程或是直接返回。表示A向B请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),数据的读写都 是由请求方A自己来完成的(不管是阻塞还是非阻塞);

weixin_45084090的博客 306

YOLOv8改进,YOLOv8添加DCNv3可变性卷积,无需编译

DCNv3在DCNv2版本上进行了改进,上一期我们在YOLOv8中添加了DCNv2,这一期我们将添加DCNv3,DCNv3代码详解可以参考链接:代码详解——可变形卷积(DCNv3)

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 5021

SAP生产订单技术性完成(TECO)操作指南与实战应用

生产订单技术关闭操作指南主要包括单笔和批量关闭两种方式,通过CO02/COHV事务码完成。

m0_47402127的博客 1932

服务器IO性能排查——iostat

iostat是sysstat命令集下的在 Linux 和 UNIX 系统上用于监控系统输入/输出设备负载的工具,它提供了 CPU 和输入/输出(I/O)使用情况的统计信息。

糖拌西红柿 2579

[明道云] -基础教学5- 明道云 40 种控件详解与场景解析

明道云工作表提供40种业务控件,涵盖文本、数值、关联、公式等类型,支持各类业务场景。文本类支持多行输入、正则校验;数值/金额类提供进度条、百分比显示等功能;关联类实现多表数据引用;公式/函数类支持复杂逻辑运算;自动化类包括打印模板、API调用等控件。合理使用这些控件可提升数据收集质量和自动化效率,同时需注意控件联动的性能影响和权限配置。关键控件包括关联记录、级联选择、公式计算等,适用于订单管理、客户信息关联等业务场景。

每日出拳老爷子的博客 8541

Linux服务器3 --- 多路IO复用技术 --- select(单进程服务端模型使用select实现一对多处理)讲解

多路IO复用技术可以监听多个网络IO上的网络事件,网络IO,一个socket就相当于一个网络IO,网络事件,网络IO上发生的读事件,写事件,异常事件等。 单进程服务器模型两个主要模块发生冲突导致我们只能实现一对一的处理,如果单进程模型加上IO复用技术,就可以实现一对多处理效果。 1、accept 函数是阻塞函数,为什么阻塞?第一个参数是serverfd,阻塞在serverfd这个socket上等事件,listen监听serverfd这个网络IO上的事件,比如读事件或者写事件,什么时候会触发读/写事件,别人给

scarificed的博客 807

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

事件处理与IO模型

服务器程序通常需要处理三类事件:I/O事件,信号及定时事件。所以,Reactor 可以理解为「来了事件操作系统直接通知,自己啥也不干,让子线程来处理读写」,而 Proactor 可以理解为「来了事件操作系统来处理,处理完再通知主线程」。这里的「事件」就是有新连接、有数据可读、有数据可写的这些 I/O 事件。这里的「处理」包含从驱动读取到内核以及从内核读取到用户空间。

weixin_44949092的博客 1133

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【Linux学习笔记54】多进程处理TCP服务器IO模型之并发阻塞

引言 这一篇笔记主要记录在TCP服务器中,如果连接端点都是阻塞的,我们应该如何处理。 TCP是面向连接的,在服务端中,需要先进行连接,再通信。因此就存在一个监听套接字,专门监听对端的连接请求。那么,当存在多个对端的连接请求的时候,当达到服务器的连接上限后,如果服务器要读其中一个端的数据的时候,就不能做其他事情,只有当一件事完成后才能做下一件事,也就是存在阻塞。为了解决这个问题,我们可以使用多进程来...

RayCongLiang的博客 442

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

《后台开发 核心技术与应用实践》 第七章,网络IO模型总结

IO有两种操作:同步IO和异步IO 同步IO: 必须等待IO操作完成后,控制权,才返回给用户进程。 异步IO:无需等待IO操作完成,就将,控制权,返回给用户进程。 四种网络IO模型 1 阻塞IO模型 2 非阻塞IO模型 3 多路IO复用模型 4 异步IO模型 阻塞和非阻塞,描述用户线程调用内核IO操作,的方式 阻塞:是指IO操作需要,彻底完成后,才返回到用户空间 非阻塞:是指I...

烟笑言子彦的博客 332

《后台开发:核心技术与应用实践》第七章网络IO模型

文章目录一、基础知识1.IO的两种操作:同步IO和异步IO2.网络中IO的操作有4种情况:3.当一个网络IO(eg,read操作),会涉及哪两个系统对象和经历哪两个阶段?二、四种网络IO模型1.阻塞IO模型2.非阻塞IO模型3.多路IO复用模型4.异步IO模型 一、基础知识 1.IO的两种操作:同步IO和异步IO 同步IO:必须等待IO操作完成后,控制权才返回给用户进程 异步IO:无需等待IO操...

喜欢打篮球的普通人 504

服务器架构设计

问题聚焦:     核心章节。     服务器一般分为如下三个主要模块:I/O处理单元(四种I/O模型,两种高效事件处理模块),逻辑单元(两种高效并发模式,有效状态机)和存储单元(不讨论)。 服务器模型 C/S模型 结构: 特点: 逻辑简单。 工作流程: I/O复用技术:select,同时监听多个客户请求。 优点:适合资源相对集中的场合。 缺点:当

晴天的专栏 2296

Python之异步IO模型实现socket并发

服务端: import socket sk = socket.socket() addr = ('127.0.0.1',8090) sk.bind(addr) sk.listen() sk.setblocking(False) # 设置非阻塞模式,accept,recv等方法均不阻塞,而是抛出异常 conn_lst = [] # 建立一个列表存储接收到的连接 del_lst = [] # 建...

phluo的博客 2864

服务器端网络编程之 IO 模型

引言 从 T 跳槽到 A 之后,我的编程语言也从 C++ 转为 了 Java。在 T 做的偏服务器端开发,而在 A 更偏向于业务开发。上周在 A 公司组内做了一个《服务器端高性能网络编程》的分享,我讶异于组内的十个人竟然没有一个人做过直接基于 TCP/IP 协议的开发,更多的是 Web 后台的业务开发。连 Java 最强大的网络库 Netty,用过的人也只有一个。但也不难理解---A...

weixin_30702887的博客 190

服务器开发之 IO 处理

服务器的主要事务是处理各种逻辑,为上千上万的用户提供特定的服务。所以,对它的要有能够应对高并发的特点,同时还要有高的响应处理能力,稳定性更是不用多说,这是第一位的,没有玩家希望自己购买的道具丢失。               下面花一个简单的服务器进程的模型图,说明服务器进程的基本事务结构,其实就是和一些他要处理的 IO 的关系。               上面的图中,服务器进程中一

天空的云 684

高性能服务器开发项目框架

服务器模型为C/S模式。 CS模型逻辑。服务器启动后,首先创建一个或多个监听socket,并调用bind函数将其绑定到服务器感兴趣的端口上,然后调用listen函数等待客户连接。服务器稳定运行后,客户端就可以调用connet函数向服务器发起连接。 由若干客户连接是随机到达的异步事件,服务器需要使用某种IO模型来监听这一事件,当监听到连接请求后,服务器就调用accept函数接受它,并分配一个逻辑单元为新的连接服务。 可以创建一个新的进程或线程作为逻辑单元。逻辑单元读取客户请求,然后处理该请求,然后将处理结果返

梅杏柿的博客 336

服务器模型选择

循环服务器指的是对于客户端的请求和连接,服务器在处理完毕一个后在处理另一个,即串行处理客户端的请求。 服务器又叫迭代服务器。循环服务器常用于UDP服务程序。UDP协议的循环服务器如下所示,在recv()函数和处理数据这两种业务之间轮询处理。 2.TCP循环服务器 相当于UDP,TCP协议的循环服务器的主处理过程中多一个accept()的过程,服务器在此等待客户端的连接,由于accept()函数为阻塞函数,所以通常情况,服务器会在此处等待。对accept()函数的不同处理是区别各种服务器类型的一个重要依据。

weixin_50866517的博客 649

使用select实现TCP并发服务器模型

本期主要分享的是对于select的使用,使用select实现TCP并发服务器模型,由于之前所用到的技术知识只能够支撑我们进行单个访问,但是有了select之后呢,我们就能够实现多用户进行访问;这也是非常符合客观需求的;

weixin_58016534的博客 2310

Linux服务器网络开发模型

linux 服务器 io 模型

redsuntim的专栏 2228
上一篇: 在git bash中使用git rebase的流程
下一篇: MySQL常见错误
houwanxing
博客等级 码龄12年 13粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值