Unix信号详解(Signal的信号说明)

signal() -函数的详细使用说明 函数用于设置特定信号的处理方式。它允许程序在接收到特定信号时执行自定义的处理函数,或者采用默认的处理方式,也可以选择忽略该信号。这些信号在不同的操作系统上可能会有一些细微的差别,但总体上它们的行为是相似的。在编写程序时,可以根据需要使用。函数或其他信号处理机制来改变这些信号的默认行为,以实现更灵活的程序控制和错误处理。这个函数接收两个参数,返回一个函数指针。以下是一个完整的示例代码,展示了如何使用。 阅读详情

signal信号机制是属于计算机异常处理机制中的一种。
signal信号属于一种异步处理异常的机制之一。
类似于我们平常在命令行上对于死循环的程序,按下ctrl-z暂时挂起,ctrl-c程序终止,这些挂起,终止信号都属于signal信号的一种,常见的几种signal信号如下图所示(供查询使用,平时并无用):
常见的SIGNAL信号类型

信号常见的术语:
1.发送信号:
先简单介绍一下进程组的概念,一个操作系统有很多进程所组成,有系统进程,应用进程。而这些进程又是以进程组来区分的。Shell里面又有前台进程组和后台进程组,前台进程组说明shell进程必须等待前台进程结束才可以读取并执行下一条指令,后台进程组顾名思义在后台进行。父进程与它的子进程处于同一进程组中,在shell上每次发送类似ctrl-c的信号都会发送到每个前台进程组中。
以下图片说明进程组的概念:
进程组的说明

发送信号常用的两种方法;

通过/bin/kill程序发送信号:

/bin/kill -9 15213
发送信号给进程15213
/bin/kill -9 -15213
如果进程前面表示为负的,说明发送信号9给15213进程组的所有信号
还有一个同名函数也可以在程序中对指定进程发送信号:

#include<sys/type.h>
#include<signal.h>

int kill(pid_t pid, int sig);

从键盘发送信号

Unix用作业(job)这个抽象概念来表示对一个命令行求值而创建的进程。在任何时刻,至多只有一个前台进程和0个或多个后台进程,而ctrl-z或者ctrl-c则会向每一个前台进程发送信号。

通过alarm函数给自身进程发送信号

alarm的函数原型:

#include<unistd.h>
unsigned int alarm(unsigned int secs);
//返回:前一次闹钟剩余的秒数,若以前没有闹钟,则设置为0

该函数即是为了到了设置的固定时间发送一次信号消息

接受消息

接受消息的时候,通常会设置一个handler函数,表示自定义收到消息后的行为该如何

前面都是些对signal介绍,接下来到了重点和难点了呀!!!

信号处理问题

一个程序接受一个信号的时候似乎很好理解,且不会出现太大的问题,但是一旦一个进程接受了多个信号的时候,问题就出现了

以下是问题的说明:

该信号如果理解成现实生活中的信号,现实中的信号也永远是异步。例如,小张和小和正在说话,这是一个顺序执行的操作。如果,这时候上司(操作系统内核)突然说了声“小张,那个文件给我处理一下了”,这就是一个异步信号,小张在接受这个信号之后就会去处理这个文件,这个就是信号处理函数,如果上司说了“那个文件给我处理一下”,这时候另一个同事说“一起去吃饭”,这时候就有两个信号了,这时候小张就先去“处理文件”的信号,再去处理“一起去吃饭”的信号,这就是待处理信号被阻塞。如果上司一直说“那个文件给我处理一下”,“那个文件给我处理一下”,这就是相同类型的信号有很多个,这时候只有第一个有用,小张就去做第一个,这就是待处理信号不会排队等待的道理

  • 待处理信号被阻塞:Unix信号函数会阻塞统一类型的待处理信号。就比如,一个程序接受了一个SIGCHLD的信号,那么在执行SIGCHLD的信号的时候,下一的SIGCHLD的信号就会被阻塞,成为待处理信号。
  • 待处理信号不会排队等待。即针对同一类型的信号,只能有一个待处理信号。例如,一个进程接受了一个SIGCHLD的信号,在执行SIGCHLD的信号处理程序的时候,来了两个SIGCHLD信号,那么只有一个SIGCHLD会成为待处理信号。
  • 系统调用可以被中断。像read,wait,accept这样的系统调用潜在地会阻塞进程一段时间,称为慢速系统调用。在某些系统中,当处理程序捕获到一个信号,被中断的系统调用在信号处理程序进行后不再返回,而是立即返回给用户一个错误条件,并将errno设置为EINTR.

接下来,用几个程序例子来说明这三个特性。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#define MAXLINE    1024   /* max line size */
#define MAXARGS     128   /* max args on a command line */
#define MAXJOBS      16   /* max jobs at any point in time */
#define MAXJID    1<<16   /* max job ID */
#define MAXBUF    100

void handler1(int sig) {
    pid_t pid; 
    if ((pid = waitpid(-1, NULL, 0)) < 0) 
        printf("waitpid error"); 
    printf("Handler reaped child %d\n", (int)pid); 
    sleep(2); 
    return;

} 
int main() {
    int i, n; 
    char buf[MAXBUF]; 
    if (signal(SIGCHLD, handler1) == SIG_ERR)
        printf("signal error"); /* Parent creates children */ 
    for (i = 0; i < 3; i++) {
        if (fork() == 0) {
            printf("Hello from child %d\n", (int)getpid());
            sleep(1);
            exit(0);
        }
    } 
    /* Parent waits for terminal input and then processes it */ 
    if((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
        printf("read"); 
    printf("Parent processing input\n"); 
    while (1)
        ; 
    exit(0);
}

输出结果为:

Hello from child 12575
Hello from child 12576
Hello from child 12577
Handler reaped child 12577
Handler reaped child 12576
<cr>
Parent processing input

可以从结果明显的看出只回收了两个孩子进程,剩下一个孩子进程变成僵尸进程

导致这个结果的原因是:等待信号不会排队.

父进程创建了三个子进程,当三个子进程结束的时候,三个进程成为僵尸进程,向父进程传递三个SIGCHLD信号,一个正在处理,一个待处理,因为同一个信号只有一个待处理信号,剩下一个信号就被抛弃,所以有一个子进程的SIGCHLD信号不被处理,一个子进程成为僵尸进程。

针对这个问题,写了一个改进版的signal1
如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#define MAXLINE    1024   /* max line size */
#define MAXARGS     128   /* max args on a command line */
#define MAXJOBS      16   /* max jobs at any point in time */
#define MAXJID    1<<16   /* max job ID */
#define MAXBUF    100

void handler1(int sig) {
    pid_t pid; 
    while((pid = waitpid(-1, NULL, 0)) > 0) 
        printf("Handler reaped child %d\n", (int)pid);
    if(errno!=ECHILD)
        printf("waitpid error");
    sleep(2); 
    return;

} 
int main() {
    int i, n; 
    char buf[MAXBUF]; 
    if (signal(SIGCHLD, handler1) == SIG_ERR)
        printf("signal error"); /* Parent creates children */ 
    for (i = 0; i < 3; i++) {
        if (fork() == 0) {
            printf("Hello from child %d\n", (int)getpid());
            sleep(1);
            exit(0);
        }
    } 
    /* Parent waits for terminal input and then processes it */ 
    if((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
        printf("read"); 
    printf("Parent processing input\n"); 
    while (1)
        ; 
    exit(0);
}

结果如下:

Hello from child 12648
Hello from child 12649
Hello from child 12650
Handler reaped child 12649
Handler reaped child 12648
Handler reaped child 12650
read:Interrupted system call

成功回收了三个子进程

重点的改动在于这几行代码:

    while((pid = waitpid(-1, NULL, 0)) > 0) 
        printf("Handler reaped child %d\n", (int)pid);
    if(errno!=ECHILD)
        printf("waitpid error");

用while循环来尽可能个获取未被回收的进程

但是为什么会出现read:Interrupted system call
原因在于:系统调用可以被中断,但是返回后不能继续,即不能自动重启

它们会返回一个错误条件

再对handler进行改进
改进的版本如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#define MAXLINE    1024   /* max line size */
#define MAXARGS     128   /* max args on a command line */
#define MAXJOBS      16   /* max jobs at any point in time */
#define MAXJID    1<<16   /* max job ID */
#define MAXBUF    100

void handler1(int sig) {
    pid_t pid; 
    while((pid = waitpid(-1, NULL, 0)) > 0) 
        printf("Handler reaped child %d\n", (int)pid);
    if(errno!=ECHILD)
        printf("waitpid error");
    sleep(2); 
    return;

} 
int main() {
    int i, n; 
    char buf[MAXBUF]; 
    if (signal(SIGCHLD, handler1) == SIG_ERR)
        printf("signal error"); /* Parent creates children */ 
    for (i = 0; i < 3; i++) {
        if (fork() == 0) {
            printf("Hello from child %d\n", (int)getpid());
            sleep(1);
            exit(0);
        }
    } 
/* Manually restart the read call if it is interrupted */ 
while ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
{
    if (errno != EINTR)  
        unix_error"read error");
}

printf("Parent processing input\n");
    while (1)
        ; 
    exit(0);
}

重点在与这一句

/* Manually restart the read call if it is interrupted */ 
while ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
{
    if (errno != EINTR)  
        unix_error"read error");
}

用while尽可能的执行read,实现对read系统调用进行自动重启。

说明singal存在的竞争问题

以下是存在竞争问题的一个例子
这里写图片描述

这个看似正常的程序,实质上存在竞争问题

在父进程fork出子进程之后,子进程执行/bin/date程序,如果此时内核调度先执行的是子进程,那么如果子进程执行完,向父进程发出SIGCHLD信号,并执行handler,handler删除了子进程的任务,此时在调度进父进程,执行addjob,此时,就会添加一个根本不存在的进程。发生了竞争错误

解决此问题的方法是:在父进程执行addjob代码之前,把SIGCHLD阻塞起来,当addjob之后再解除阻塞,当然子进程也会继承父进程的阻塞信号集,此时需要在子进程解除阻塞信号,让子进程正常执行。

表现为代码,即是如下代码:

这里写图片描述

接下来放一个比较如何验证竞争问题的Fork代码,实质上就是在Fork之后,分别有50%的几率执行父进程或者子进程

以下是代码:
这里写图片描述

Unix 信号大全 信号的概念:   首先,每个信号都有一个名字。这些名字都以三个字符 S I G开头。例如,S I G A B RT是夭折 信号,当进程调用a b o r t函数时产生这种信号。S I G A L R M是闹钟信号,当由a l a r m函数设置的时 间已经超过后产生此信号。 V 7有1 5种不同的信号, S V R 4和4 . 3 + B S D均有3 1种不同的信号。 在头文件中,这 阅读详情

相关推荐

C语言:高级并发操作(信号)

同步和异步的使用。异步事件处理的两种方法:查询法、通知法。(单核机器不存在异步)

m0_58233509的博客 1455

linux 信号 命令,Linux信号列表详解

我们运行如下命令,可看到Linux支持的信号列表:~$ kill -l1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR213) SIGPIPE 14) SIGALRM 15) SIGTERM 17...

weixin_33514277的博客 622

Hermes V0.10.0:官方UI几乎无Bug版

如果你还在观望Hermes,现在可能是最好的入局时机。 因为网页端来了,门槛降到了最低。 如果你已经是Hermes用户,升级就对了。 因为0.9.0的更新,值得一试。

weixin_66295112的博客 2046



signal() 函数详解 signal()函数详解: 在 这个头文件中。 signal(参数1,参数2); 参数1:我们要进行处理的信号。系统的信号我们可以再终端键入 kill -l查看(共64个)。其实这些信号时系统定义的宏。 参数2:我们处理的方式(是系统默认还是忽略还是捕获)。 一般有3中方式进行操作。 (1)eg: signal(SIGINT ,SI

lvchen19880427的专栏 962

RocketMQ5.3.0-control-多 Master 多 Salve-异步复制-集群搭建

RocketMQ5.3.0-control-多 Master 多 Salve-异步复制-集群搭建(详细文档)

m0_52369979的博客 729

ADS2023实战:2.4GHz超外差接收机从设计到链路预算全流程解析

本文以ADS 2023软件为平台,详细解析了2.4GHz超外差接收机从核心指标定义、架构原理到完整链路搭建与仿真的全流程。通过实战演练,重点阐述了如何利用ADS进行谐波平衡仿真和链路预算分析,以量化评估系统增益、噪声系数等关键性能,为射频工程师提供了一套从理论到仿真的系统级设计方法。

herb5的博客 816

Unix信号处理

当更改信号动作时,如果sa_handler指向一个信号捕捉函数(不是常数SIG_IGN或者SIG_DFL),则sa_mask字段说明了一个信号集,在调用信号捕捉函数之前,该信号集要加到进程的信号屏蔽集。比较特殊的是,exec函数将原先设置为要捕捉的信号都更改为默认动作,其他信号的状态则不变(一个进程原先要捕捉的信号,当其执行一个新程序后,就自然不能再被捕捉了,因为信号捕捉函数的地址很可能在所执行的新程序文件中已无意义)。当捕捉到一个信号时,进入信号捕捉函数,此时当前的信号被自动加到进程的信号屏蔽字中。

weixin_43979090的博客 1041

AI Agent核心架构解析:从Tool、Skill到MCP协议的智能体构建实战

在人工智能领域,大语言模型(LLM)赋予了AI自主规划与决策的能力,推动了智能体(Agent)技术的演进。其核心原理在于构建一个具备感知、规划、行动与反思能力的自主系统。这一架构的技术价值在于将AI从被动应答升级为主动执行复杂任务的工作伙伴,显著提升了自动化水平与问题解决效率。应用场景广泛覆盖了市场分析、自动化办公、智能客服与垂直领域集成等。本文聚焦于实现这一能力的关键组件:基础工具(Tool)、组合技能(Skill)与标准化协议(MCP)。其中,Skill通过封装多个Tool形成可复用的高级能力,而MCP

chuannaoxuan4674的博客 318

Unix信号

信号 1. 概念: 信号是软件中断,提供了一种处理异步事件的方法。 2. 产生信号: 终端: 如按Delete键,产生SIGINT信号 硬件异常产生信号: 除数为0,无效的内存引用 进程调用kill函数 kill命令 软件产生的信号: 如SIGURG, SIGPIPE, SIGALRM(进程设置的定时器超时) 三种处理方式: 忽略 捕捉 执行默认动作 常见信号: SIGHUP SIGIN...

EverlightGe 273

SAP前台处理:业务伙伴维护(客户主数据和供应商主数据)之基础视图 <BP>

这里主要讲解BP业务伙伴主数据中和财务相关的一些内容,包括基础视图数据,采购视图数据,销售视图数据,公司代码视图数据; S4统一了供应商和客户,从事务代码上:不再使用FD01和FK01进行维护,而使用事务代码BP统一维护;

SAP.David.Gao的博客 3455

开源Agent Skill让AI画图不再翻车:从数据到专业图表全流程

在人工智能与数据可视化交叉领域,让模型直接生成图表往往伴随字体乱码、坐标轴密集、配色失调等高频问题。Agent Skill作为一种可复用的能力封装机制,将专业绘图流程固化为标准化操作手册,从数据特征识别、图表类型决策到代码生成与渲染校验形成完整闭环。它不再依赖临时提示词的一次性发挥,而是让AI按领域专家的思维执行任务,显著提升出图质量与稳定性。这种能力在数据分析报告、运营日报、论文插图等场景具有广泛实用价值,尤其适用于需要快速产出规范化图表的工作流。本文即从这一技术范式出发,介绍一个GitHub上获得2.5

weixin_33851429的博客 931

Unix中Signal信号的不同

Unix系统signal函数的不同 (1)函数说明 在signal函数中,有两个形参,分别代表需要处理的信号编号值和处理信号函数的指针。它主要是用于前32种非实时信号的处理,不支持信号的传递信息。但是由于使用简单,易于理解,因此在许多场合被程序员使用。 对于Unix系统来说,使用signal函数时,自定义处理信号函数执行一次后失效,对该信号的处理回到默认处理方式。下面以一个例子进行说明,例如一程...

weixin_34228617的博客 87

如何做好软件需求分析?

软件需求分析也称为系统需求分析或需求分析工程等,是开发人员经过深入细致的调研和分析,准确理解用户和项目的功能、性能、可靠性等具体要求,将用户非形式的需求表述转化为完整的需求定义,从而确定系统必须做什么的过程。软件开发一般包括:可行性分析、需求分析、软件设计、软件开发、软件测试、软件实施、软件服务等步骤,需求分时软件开发的第一步骤。用户需求分析是指在系统设计之前和设计、开发过程中对用户需求所作的调查与分析,是系统设计、系统完善和系统维护的依据。

qq_41854911的博客 1415

signal函数和sigactiion函数的对比

signal()和sigaction()

hitxingkong的专栏 1066

21天教你学会PCIe专栏(14)--安全性考虑

1.1 定义安全性(Security):安全性是指保护系统免受未经授权的访问、攻击和破坏,确保数据的机密性、完整性和可用性。1.2 重要性数据保护:保护敏感数据,防止数据泄露和篡改。系统防护:防止恶意攻击,确保系统的稳定性和可靠性。合规性:满足行业标准和法律法规的要求,避免法律风险。用户信任:提高用户对系统的信任度,增强市场竞争力。通过今天的学习,你应该对PCIe安全性的重要性和常见威胁有了深入的了解,掌握了实施安全措施的方法和工具,以及安全开发的最佳实践。

xiaoheshang_123的博客 850

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

10.3 signal函数

UNIX系统的信号特性的最简单的接口就是signal函数: #include <signal.h>void (*signal(int signo, void(* func)(int)))(int); Returns:previous disposition of signal(see following)if OK,SIG_ERR on error. 函数si...

weixin_30436891的博客 73

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

GO Signal

包提供了对操作系统信号的访问和处理。信号是进程之间通信的一种方式,通常由操作系统生成,表示某些事件发生,比如进程终止、挂起、或者其他异步事件。结合HTTP服务器和信号捕获,可以实现优雅地关闭服务器,确保在接收到。有时我们可能不希望处理某些信号,而是忽略它们。信号时,完成当前处理的请求后再关闭服务器。以下是一个简单的Go程序,展示如何捕获。包可以捕获这些信号并做出相应的处理。信道使用,用于异步接收信号。Go中的信号处理主要通过。

GitHub个人仓库地址:https://github.com/feiyuluoye ; 个人塔罗牌占卜平台:http://118.126.82.12:8080/ ; 欢迎广大Coding友共同交流讨论。 907

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

signal 函数

ignal 编辑 sig是传递给它的唯一参数。执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。 目录 1函数名: signal 2注意点 1函

wsss2009的专栏 636

Python 库手册:signal 系统信号处理模块

Python 的 signal 模块提供了用于处理 Unix 风格信号的机制,主要用于与操作系统交互,响应如终止、挂起、中断等信号事件。handler:处理函数,或特殊值如 signal.SIG_IGN(忽略)或 signal.SIG_DFL(默认行为)signalnum:信号编号(如 signal.SIGTERM)signalnum:信号编号(如 signal.SIGINT)(2)定时器超时控制(如设置请求或函数的超时时间)。(1)优雅关闭程序(如处理 SIGINT 中断)。

qq_41176800的博客 958

UNIX信号小结(2)

早期的UNIX信号机制是不可靠的,原因在于信号可能丢失。主要体现在:① signal函数中对信号处理的设置 ② 无法阻塞信号讨论不可靠机制之前,先介绍一下signal函数和sigaction函数,signal函数接口为void ( *singal(int signo,void (*func)(int)))(int) 看起来非常复杂,大意就是signal函数有两个参数,一个是int型的signo(也就是某类信号)一个void型的函数指针(该函数有一个int参数)。signal函数返回一个void型的函数指针,

nepepl的专栏 656

Signal-hook 项目教程

Signal-hook 是一个用于处理 Unix 信号的 Rust 库。以下是项目的目录结构及其介绍: ``` signal-hook/ ├── examples/ # 示例代码 │ ├── signal-hook-async-std/ │ ├── signal-hook-mio/ │ ├── signal-hook-registry/ │ ├── signal-...

gitblog_00476的博客 464

信号处理入门:signal与SIGINT

摘要:本文介绍了信号处理的基础知识,重点解析了SIGINT信号及其应用场景。信号是操作系统通知进程事件发生的异步机制,SIGINT作为常见中断信号(通常由Ctrl+C触发),可用于实现进程的优雅终止。文章通过Python代码示例演示了如何捕获和处理SIGINT信号,并绘制序列图说明信号处理流程。同时探讨了实际应用场景、可重入性等高级主题,推荐了GNU Libc等延伸阅读资源,为系统编程入门者提供了实用的信号处理指南。(149字)

always_TT的博客 374

Linux中的信号

信号是UNIX系统响应某些状况而产生的事件,通常是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等。信号模拟的是硬件中断方式,它的传递信息量很少,可以用来做进程间的通知或者错误的警告等。信号就是进程间通信的一种方式,它采用异步的工作方式。

2301_80657297的博客 330

UNIX下C语言编程与实践38-UNIX 信号操作:signal 函数与信号捕获函数的编写

本文介绍了UNIX信号处理的核心函数signal及其增强替代方案sigaction。signal函数作为基础接口,可实现信号的默认处理、忽略和捕获三种核心功能,但存在兼容性差、不支持信号掩码等局限性。文章详细解析了signal函数的参数规范、返回值处理,并通过实例演示了三种典型使用场景。重点强调了信号捕获函数的编写规范,包括禁止调用不可重入函数、使用volatile修饰全局变量等关键注意事项。针对复杂场景,推荐使用sigaction函数,其支持信号掩码、自动重启系统调用和获取信号附加信息等增强功能

文石_2009的博客 946

signal信号说明

<br />转载:http://blog.youkuaiyun.com/ljx0305/archive/2008/09/09/2904056.aspx<br />SIGHUP     终止进程     终端线路挂断<br />SIGINT     终止进程     中断进程<br />SIGQUIT   建立CORE文件终止进程,并且生成core文件<br />SIGILL   建立CORE文件       非法指令<br />SIGTRAP   建立CORE文件       跟踪自陷<br />SIGBUS   建立

Leon_smile的专栏 851
上一篇: Mac和Linux下的echo的区别
下一篇: leetcode 300.Longest Increasing Subsequence
写代码的柯长
博客等级 码龄11年 84粉丝 52原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值