Nginx内核

13 篇文章 0 订阅
1 篇文章 0 订阅

AUTHOR:闫小雨

TIME:2024-05-20


目录

一、链表(Linked List)

1、链表的基本结构

2、链表的类型:

3、链表的操作

4、链表的优点:

5、链表的缺点:

二、二叉树、红黑树

1、二叉树:

1. 介绍:

2. 类型:

3. 优点:

4. 缺点:

2、红黑树:

1. 介绍:

2. 类型:

3. 优点:

4. 缺点:

三、socket套接字

1、介绍:

2、类型:

3、优点:

4、缺点:

5、原IP、原端口 和 目标IP、目标端口

6、Socket的位置

7、传输层、网络层、链路层

8、内核空间与用户空间

9、套接字(Socket)与端口绑定

10、网络优化与逻辑优化

11、Linux中的网络工作原理与I/O原理

12、Epoll

四、I/O阻塞

五、硬中断、软中断

六、操作系统内核

七、Nginx内建变量(内置变量)

1、内置变量

2、内置预定义变量

3、curl命令一些常用选项和具体的例子


一、链表(Linked List)

链表是一种数据结构,数据存储中可以不连续,它通过一系列节点(Node)来存储元素,每个节点包含两个部分:一是元素本身的数据域(Data Field),二是指向下一个节点的指针域(Pointer Field)或链接(Link)。如果链表有一个指向第一个节点的指针(头指针或首元指针),那么从该指针出发就可以访问链表中的所有节点。

链表常用于实现需要频繁插入和删除操作的数据结构,如栈(Stack)、队列(Queue)等。

1、链表的基本结构

  • 节点(Node)
    • 数据域(Data Field):存储实际的数据值。
    • 指针域(Pointer Field):存储对下一个节点的引用(指针或链接)。对于链表的最后一个节点,这个指针通常设置为null或None(在某些编程语言中)以表示链表的结束。
  • 头指针(Head Pointer)
    • 指向链表的第一个节点。通过头指针,我们可以遍历链表并访问其所有节点。

2、链表的类型:

  1. 单向链表:链表中的节点只能单方向遍历,即每个节点有一个指向下一个节点的指针,但没有指向前一个节点的指针。
  2. 双向链表:链表中的节点有两个指针,一个指向前一个节点,一个指向下一个节点,从而可以从任一节点向前或向后遍历链表。
  3. 循环链表:链表中的最后一个节点指向头节点,从而形成一个循环。单向链表和双向链表都可以是循环的。
  4. 带哨兵节点的链表:在链表头部添加一个哨兵节点(或称为哑节点),这个节点不存储任何数据,它的作用主要是简化对链表头部的操作。

3、链表的操作

  • 插入(Insertion):在链表的开头、中间或结尾插入新的节点通常都很简单,只需调整一些指针的引用即可。
  • 删除(Deletion):删除链表中的节点也只需要调整一些指针的引用,并将要删除的节点从链表中分离出来。

4、链表的优点:

  • 动态分配空间:链表可以根据需要动态地分配和释放存储空间。
  • 插入和删除操作方便:在链表中插入或删除节点通常只需要修改相关节点的指针,而不需要移动大量数据。

5、链表的缺点:

  • 访问元素需要从头开始遍历:与数组不同,链表不能通过索引直接访问元素,而需要从头节点开始遍历链表。
  • 需要额外的空间存储指针:链表中的每个节点都需要额外的空间来存储指向下一个节点的指针。

二、二叉树、红黑树

1、二叉树:

1. 介绍:

二叉树是树形结构的一个重要类型。每个节点最多只能有两棵子树,且有左右之分。二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。

2. 类型:

二叉树有很多类型,主要有:

  1. 满二叉树:如果一棵二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树。
  2. 完全二叉树:深度为k,有n个节点的二叉树当且仅当其每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树。
3. 优点:
  1. 结构简单:二叉树的存储结构及其算法都较为简单。
  2. 查找效率高:对于二叉排序树(Binary Sort Tree),既可以保证数据的检索速度,也可以保证数据的插入、删除、修改的速度。
4. 缺点:
  1. 空间利用率:顺序存储可能会浪费空间(在非完全二叉树的时候),但读取某个指定的结点的时候效率比较高。链式存储相对于二叉树,浪费空间较少,但读取某个结点的时候效率偏低。
  2. 遍历效率:二叉树的遍历可能需要从头节点开始,效率可能低于其他数据结构如数组。

2、红黑树:

根节点必须是黑的

1. 介绍:

红黑树是一种自平衡的二叉搜索树,它在满足二叉搜索树特性的基础上,通过引入颜色的概念和一系列性质,使得树的左右子树高度差不会超过两倍,从而保证了最坏情况下基本动态集合操作的时间复杂度为O(log n)。红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单。

解决用户进程阻塞:

当数据到达等待队列时,通过红黑数找到对应的描述符,延后进行异步读取,读取完之后加入就绪队列(加入就绪队列只会把描述符加进去)然后通知用户进程来读数据,数据接收过程中的阻塞。

2. 类型:

红黑树本身并不是一种类型,而是一种特殊的二叉树结构。它并没有像普通二叉树那样的“类型”分类,但根据应用的不同,可能会有不同的变种或实现方式。

3. 优点:
  1. 平衡性:红黑树通过颜色和规则保持了树的平衡,使得树的高度不会过高,从而保证了查找、插入和删除操作的时间复杂度为O(log n)。
  2. 高效性:红黑树的平均统计性能要强于AVL树,因为它对之进行平衡的代价较低。
4. 缺点:
  1. 实现复杂:红黑树的实现需要遵守一系列规则,如颜色规则、父子节点颜色规则、旋转规则等,这使得实现起来相对复杂。
  2. 调整树结构:在插入或删除节点时,可能需要调整树的结构以保持平衡,这可能会带来额外的时间消耗。

三、socket套接字

1、介绍:

Socket套接字是网络中不同主机上的应用进程之间进行双向通信的端点的抽象。它实际上是一个编程接口,提供了应用层进程利用网络协议交换数据的机制。Socket上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口。可以将Socket看作不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。

2、类型:

Socket套接字主要有三种类型:

  1. 流式套接字(SOCK_STREAM):这种套接字提供可靠的、面向连接的通信流。在数据传输过程中,数据会按照发送的顺序到达接收端,不会出现乱序的情况。TCP协议通常使用流式套接字。
  2. 数据报套接字(SOCK_DGRAM):数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。UDP协议通常使用数据报套接字。
  3. 原始套接字:原始套接字允许对较低层次的协议(如IP或ICMP)直接访问。这通常用于执行复杂的网络协议分析或开发新的网络协议。
3、优点:
  1. 传输数据为字节级:Socket套接字以字节为单位进行数据传输,这使得数据的传输和处理更加灵活和高效。
  2. 传输数据可自定义:Socket套接字允许用户自定义传输的数据内容和格式,这使得数据交换更加灵活。
  3. 传输数据时间短,性能高:由于Socket套接字直接在网络协议栈上进行操作,因此数据传输的效率很高,适用于需要高性能通信的场景。
  4. 适合于客户端和服务器端之间信息实时交互:Socket套接字支持双向通信,因此非常适合于客户端和服务器之间的实时信息交互。
  5. 可以加密,数据安全性强:Socket套接字支持使用加密技术来保护传输的数据,提高了数据的安全性。
4、缺点:
  1. 需对传输的数据进行解析:由于Socket套接字以字节为单位进行数据传输,因此在接收端需要对接收到的数据进行解析和转换,增加了开发的复杂性。
  2. 对开发人员的开发水平要求高:Socket套接字的编程需要深入了解网络协议和操作系统底层的知识,对开发人员的技能要求较高。
  3. 相对于Http协议传输,增加了开发量:与基于Http协议的传输方式相比,使用Socket套接字进行通信需要编写更多的代码和处理更多的细节,增加了开发的工作量。

5、原IP、原端口 和 目标IP、目标端口

  • 在网络通信中,原IP原端口是发送方(或称为源)的IP地址和端口号。目标IP目标端口是接收方(或称为目标)的IP地址和端口号。它们处于应用层和传输层之间,在传输层和网络层中非常重要,用于路由和寻址。

6、Socket的位置

  • Socket处于应用层和传输层之间。它提供了一种机制,让应用层能够与传输层进行交互,从而发送和接收数据。
  • 使用Socket,应用程序可以无需关心底层网络通信的细节(如封包、拆包、数据校验等),只需通过简单的命令或API与远程服务器建立连接并发送数据。

7、传输层、网络层、链路层

传输层和网络层成为协议层,链路层又叫驱动层

  • 传输层:负责端到端的通信,确保数据的可靠传输。主要协议包括TCP(传输控制协议)和UDP(用户数据报协议)。
  • 网络层:负责将数据从源主机传输到目标主机。主要协议是IP(互联网协议)。
  • 链路层(又称数据链路层或驱动层):负责在相邻节点之间传输数据帧。它处理与物理介质相关的所有事项,如网络接口卡(NIC)和驱动程序。

8、内核空间与用户空间

  • 内核空间:是操作系统内核运行的空间,它管理系统的硬件和软件资源,如CPU、内存、磁盘等。传输层、网络层和链路层的操作主要在内核空间中完成
  • 用户空间:是用户应用程序运行的空间。应用层程序在这里运行(应用层也称位用户空间),并通过系统调用(如Socket API)与内核空间进行交互。

9、套接字(Socket)与端口绑定

  • 当一个应用程序想要在网络上进行通信时,它会创建一个Socket,并将该Socket绑定到一个特定的端口上。这样,其他应用程序就可以通过该端口与该应用程序进行通信。应用层连接都会使用套接字,套接字会绑定端口

10、网络优化与逻辑优化

  • 网络优化:涉及提高网络通信的效率和性能,包括优化网络拓扑结构、合理分配带宽资源、使用缓存技术等,就称为网络优化。
  • 逻辑优化:主要涉及软件或算法的设计和实现,以提高程序的性能、减少资源消耗或改善用户体验。例如,在组合逻辑电路设计中使用真值表最小化方法、电路代数化简方法等。

11、Linux中的网络工作原理与I/O原理

  • 在Linux中,网络数据的传输和I/O操作通常通过系统调用来实现。当应用程序需要发送或接收数据时,它会通过Socket API发起系统调用,这些调用会被传递给内核空间中的网络协议栈进行处理,也就是说网络在Linux工作原理就是IO原理。
  • 网络协议栈会负责将数据封装成适当的格式,并通过网络设备和驱动程序将其发送到目标主机或接收来自目标主机的数据。
  • 在IO操作中,Linux使用了各种机制来提高性能和效率,如异步I/O缓冲I/O等。这些机制允许应用程序在等待数据到达或写入磁盘时继续执行其他任务,从而提高了整体的响应速度和吞吐量。

12、Epoll

  • Epoll是Linux内核中的一种I/O多路复用机制,用于监控多个文件描述符的状态变化。当某个文件描述符就绪时(例如,有数据可读或可写),Epoll会通知应用程序进行相应的处理。
  • 与传统的select和poll机制相比,Epoll在处理大量文件描述符时具有更高的效率和更好的性能。

四、I/O阻塞

I/O模型分为5种,分别是:阻塞I/O、非阻塞I/O、I/O复用、信号驱动I/O以及异步I/O

I/O阻塞指的是在进行输入/输出(I/O)操作时,如果数据没有准备好或者无法立即完成,那么线程或进程就会被挂起,直到数据准备好或操作完成为止。这种情况下,线程或进程会一直等待,不能执行其他任务,造成了资源的浪费,阻塞一般在建立连接和传输数据的时候。

阻塞I/O的优点

  1. 模型简单:阻塞I/O模型实现起来相对简单,对于需要快速构建原型的应用来说,这是一个很好的点。
  2. 开发难度低:由于模型简单,开发人员可以更容易地理解和实现阻塞I/O。
  3. 资源利用率高(在单线程环境):在单线程环境中,当I/O操作阻塞时,CPU可以去做其他事情(比如执行其他线程或进程),从而提高了CPU的利用率。

阻塞I/O的缺点

  1. 效率低下:在多线程或多进程环境中,如果大量线程或进程都在等待I/O操作完成,那么这些线程或进程将处于阻塞状态,无法执行其他任务,这会导致资源的浪费。
  2. 不适用于高并发场景:在高并发场景下,每个连接都可能需要一个独立的线程或进程来处理,这将导致大量的线程或进程被阻塞在I/O操作上,从而消耗大量的系统资源。
  3. 响应性差:对于需要快速响应的应用来说,阻塞I/O可能会导致用户等待时间过长,从而影响用户体验。

为了克服阻塞I/O的这些缺点,人们开发了非阻塞I/O(Non-blocking I/O)、异步I/O(Asynchronous I/O)等更高效的I/O模型。这些模型允许应用程序在等待I/O操作完成的同时,继续执行其他任务,从而提高了系统的整体性能和响应性。

五、硬中断、软中断

1、硬中断(Hardware Interrupt)

硬中断,也叫异步中断。硬中断是由硬件设备依照CPU时钟信号产生的,意味着中断发生具有随机性和突发性,能够在指令正在执行时发生。例如键盘中断。硬中断是由硬件产生的,比如,像磁盘,网卡,键盘等。

  • 硬中断是一种异步信号,用于在轮询循环、等待外部事件方面避免浪费处理器的宝贵时间。
  • 硬中断是由硬件设备(如磁盘、网卡、键盘、时钟等)产生的中断请求。当这些设备需要CPU的注意来执行某些任务时,它们会向CPU发送中断信号。
  • 硬中断可以分为外部中断和内部中断。外部中断由外部设备引起,如响应I/O设备、中断控制器(PIC)所发出的中断请求等。内部中断则由CPU内部发生的事件引起,如运算错误、时间片轮转、指令集拓展等。

2、软中断(Soft Interrupt)

软中断,也叫同步中断。软中断是由CPU执行中断产生指令时产生,是由程序预先实现好的,不是随机的。

  • 软中断是一种由软件方式模拟的中断,用于实现宏观上的异步执行效果。虽然它与硬中断在概念上有所相似,但软中断不是由硬件设备产生的。
  • 软中断通常用于处理硬中断服务程序对内核的中断,如当硬件中断产生时,可能需要内核进行某些操作(如I/O操作),此时就会产生软中断。
  • 软中断是由内核机制的触发事件引起的,如进程运行超时等。也有大量的软中断是由于和硬件有关的中断引起的,例如当打印机端口产生一个硬件中断时,会通知和硬件相关的硬中断,硬中断就会产生一个软中断并送到操作系统内核里。

六、操作系统内核

作系统内核是操作系统的核心部分,也是操作系统其他组件的基础。它是一组程序模块,作为安全软件来提供支持进程并发执行的基本功能和基本操作,通常驻留在内核空间且运行于内核态,具有访问硬件设备和所有内存空间的权限,是仅有的能够执行特权指令的程序。

操作系统内核的主要功能:

  1. 资源抽象:用软件抽象硬件资源,简化对其所执行的操作,屏蔽低层的物理细节,如提供设备驱动程序、创建虚拟设备等。
  2. 资源分配:把所抽象的各种资源分配给多个应用程序使用,并负责回收资源。
  3. 资源共享:根据资源的类型和特性,提供不同的机制以确保进程获得所需资源,允许进程共享资源并提供资源的互斥与同步机制。

七、Nginx内建变量(内置变量)

nginx可以使用变量简化配置与提高配置的灵活性,所有的变量值都可以通过这种方式引用:

$变量名

而nginx中的变量分为两种,自定义变量内置预定义变量

1、内置变量

可以在sever,http,location等标签中使用set命令(非唯一)声明变量

set $变量名 变量值

注意:nginx中的变量必须都以$开头。

nginx的配置文件中所有使用的变量都必须是声明过的,否则nginx会无法启动并打印相关异常日志

nginx变量的一个有趣的特性就是nginx中没一个变量都是全局可见的,而他们又不是全局变量。比如下面这个例子

location a/ {
  return 200 $a
}

location b/ {
 set $a hello nginx
 return 200 $a
}

由于变量是全局可见的所以nginx启动不会报错,而第一个location中并不知道$a的具体值因此返回的响应结果为一个空字符串。

在不同层级的标签中声明的变量性的可见性规则如下:

  1. location标签中声明的变量中对这个location块可见
  2. server标签中声明的变量对server块以及server块中的所有子块可见
  3. http标签中声明的变量对http块以及http块中的所有子块可见
2、内置预定义变量

内置预定义变量即无需声明就可以使用的变量,通常包括一个http请求或响应中一部分内容的值,以下为一些常用的内置预定义变量

变量名

定义

$arg_name

请求中的的参数名,即“?”后面的arg_name=arg_value形式的arg_name

$arg_PARAMETER

GET请求中变量名PARAMETER参数的值。

$args

这个变量等于GET请求中的参数,不包含"?"。

$binary_remote_addr

客户端地址的二进制形式, 固定长度为4个字节

$body_bytes_sent

传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的“%B”参数保持兼容

$bytes_sent

传输给客户端的字节数 (1.3.8, 1.2.5)

$connection

TCP连接的序列号

$connection_requests

TCP连接当前的请求数量

$content_length

请求头中的Content-length字段。

$content_type

请求头中的Content-Type字段。

$cookie_COOKIE

cookie COOKIE的值。

$cookie_name

请求头中的Cookie字段中NAME的值。

$document_root

当前请求的文档根目录或别名 或 当前请求在root指令中指定的值。

$document_uri

与$uri相同。

$host

请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称,使用虚拟主机名。(处理请求的server的server_name指令的值)。值为小写,不包含端口。

$hostname

主机名,机器名使用 gethostname系统调用的值

$http_HEADER

HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值);

$http_name

匹配任意请求头字段; 变量名中的后半部分“name”可以替换成任意请求头字段,如在配置文件中需要获取http请求头:“Accept-Language”,那么将“-”替换为下划线,大写字母替换为小写,形如:$http_accept_language即可。

$http_referer

请求头中的Referer字段。

$http_user_agent

请求头中的User-Agent字段。

$https

如果开启了SSL安全模式,值为“on”,否则为空字符串。

$is_args

如果$args设置值为"?",否则为""。

$limit_rate

如果使用了limit_rate指令,这个变量表示当前的限速。

$msec

当前的Unix时间戳 (1.3.9, 1.2.6)

$nginx_version

当前运行的nginx版本号。

$pid

工作进程的PID

$pipe

如果请求来自管道通信,值为“p”,否则为“.” (1.3.12, 1.2.7)

$proxy_protocol_addr

获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串。(1.5.12)

$query_string

与$args相同。

$realpath_root

当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径。

$remote_addr

客户端的IP地址。

$remote_port

客户端的端口。

$remote_user

用于HTTP基础认证服务的用户名, 如果使用了基本身份验证,这个变量表示用户名。

$request

代表客户端的请求地址

$request_body

客户端的请求主体,这个变量仅在请求方法为POST、PUT或PATCH时可用也可在location中使用,将请求主体通过proxy_pass, fastcgi_pass, uwsgi_pass, 和 scgi_pass传递给下一级的代理服务器。

$request_body_file

将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off, uwsgi_pass_request_body off, or scgi_pass_request_body off 。

$request_completion

如果请求成功,值为”OK”,如果请求未完成或者请求不是一个范围请求的最后一部分,则为空。

$request_filename

当前连接请求的文件路径,由root或alias指令与URI请求生成。

$request_length

请求的长度 (包括请求的地址, http请求头和请求主体)

$request_method

这个变量是客户端请求的动作,HTTP请求方法,通常为GET或POST。

$request_time

处理客户端请求使用的时间; 从读取客户端的第一个字节开始计时,单位为秒,精确到毫秒。

$request_uri

这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。不包含主机名

$scheme

请求使用的Web协议, “http” 或 “https”比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;

$sent_http_HEADER

HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type…;

$sent_http_name

可以设置任意http响应头字段; 变量名中的后半部分“name”可以替换成任意响应头字段,如需要设置响应头Content-length,那么将“-”替换为下划线,大写字母替换为小写,形如:$sent_http_content_length 4096即可。

$server_addr

服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中。在完成一次系统调用后可以确定这个值。

$server_name

服务器名,即Host请求头字段或服务器名指令的值。

$server_port

请求到达服务器的端口号。

$server_protocol

请求使用的协议版本,"HTTP/1.0"或"HTTP/1.1"。

$status

HTTP响应状态码。

$tcpinfo_rtt

数据包从发送者到接收者再返回所需的时间。评估网络延迟和性能的关键指标。

$tcpinfo_rttvar

RTT的变化或偏差。帮助TCP算法确定何时重传丢失的数据包和调整发送速率。

$tcpinfo_snd_cwnd

TCP用于控制发送速率的机制,表示发送者可以连续发送但尚未收到确认的数据量。当窗口满时,发送者需停止发送并等待确认,这是流量控制的一部分。

$tcpinfo_rcv_space

接收者告诉发送者它可以接收多少未确认数据的量。防止发送者发送过多数据导致接收者缓冲区溢出,是流控制的一部分。

$time_iso8601

服务器以ISO 8601格式记录的当前时间。

$time_local

通用日志格式(Common Log Format)的当前时间。

$uri

请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如”/foo/bar.html”。

3、curl命令一些常用选项和具体的例子

命令

描述

-X 或 --request

指定HTTP方法(如GET、POST、PUT等)。例如:-X POST。

-o 或 --output

将输出写入文件而不是stdout。例如:-o output.txt。

-O 或 --remote-name

根据远程文件名保存输出,适用于下载。

-d 或 --data

发送POST数据。例如:-d "key=value"。

-H 或 --header

添加自定义HTTP头。例如:-H "Authorization: Bearer TOKEN"。

-i 或 --include

在输出中包含HTTP头信息。

-s 或 --silent

禁止输出进度信息,静默模式。

-L 或 --location

自动处理重定向。

-k 或 --insecure

允许不安全的SSL连接,忽略证书验证。

-v 或 --verbose

使输出更详细,显示通信过程的信息。

-A 或 --user-agent

设置用户代理字符串。

--limit-rate

限制传输速率,例如:--limit-rate 100K限制到每秒100KB。

--compressed

请求服务器返回压缩的内容并自动解压。

-m 或 --max-time

设置最大处理时间(秒)。例如:-m 30表示超时时间为30秒。

-I 或 --head

只显示HTTP头信息,不下载实际内容。

-u 或 --user

用于HTTP身份验证,格式为user:password。例如:-u admin:secret。-s 或 --silent 禁止输出进度信息,静默模式。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫叫闫小雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值