SRS流媒体服务器——Forward集群搭建和源码分析

SRS流媒体服务器——Forward集群搭建和源码分析

目录

  1. Forward集群原理
  2. RTMP流转发(Forward)部署实例
  3. Forward集群源码分析

SRS安装部署相关内容:

  1. SRS流媒体服务器——单机环境搭建和源码目录介绍
  2. SRS流媒体服务器——Forward集群搭建和源码分析
  3. SRS流媒体服务器——Edge集群搭建
  4. SRS流媒体服务器——WebRTC推拉流演示
  5. SRS流媒体服务器——SRS4.0 WebRTC⼀对⼀通话环境搭建与逻辑分析

SRS部分源码分析相关内容:

  1. SRS流媒体服务器——基本流程简单分析
  2. SRS流媒体服务器——RTMP端⼝监听逻辑分析
  3. SRS流媒体服务器——RTMP推流、拉流创建连接
  4. SRS流媒体服务器——服务器读取RTMP推流数据
  5. SRS流媒体服务器——服务器给RTMP拉流端转发数据

1. Forward集群原理

  1. Forward 表示向前、前头的、发送等意思。
  2. 在SRS中可以理解为把Master节点获得直播流⼴播(转发)给所有的Slave节点,master节点由多少路直播流,那么在每个slave节点也会多少路直播流。
  3. 注:在SRS中还有另外⼀种集群⽅式,edge⽅式。注意两种⽅式的⽤词不同。
    a. 在Forward模式中,中⼼节点叫Master,边缘节点叫Slave。
    b. 在edge模式中,中⼼节点叫origin(源站),边缘节点叫做edge。

1. 适用场景

在这里插入图片描述

  1. Forward适合搭建⼩型集群。
  2. 推流者推流给master,那么master就会Forward到每⼀个Slave,那么在slave节点上不论需不需要都会有master过来的流。
  3. 如果推流者的数量为10,那么master到slave之间的带宽就是:带宽=10 *slave的个数 *直播流码率,随着slave的增多,master的出⼝带宽会不断提⾼。
  4. ⽽现实是,在某些slave节点其实没有⼈看,这样就造成了master到slave之间的带宽浪费。
  5. 所以说Forward适合⽤于搭建⼩型集群。

2. RTMP流转发(Forward)部署实例

  1. SRS可以将送到SRS的流转发给其他RTMP服务器,实现简单集群/热备功能,也可以实现⼀路流热备
    a. 如编码器由于带宽限制,只能送⼀路流到RTMP服务器,要求RTMP服务器能将这路流也转发给其他RTMP备⽤服务器,实现主备容错集群。
  2. 假设服务器的IP是:8.141.75.248
  3. Forward就是SRS将流拷⻉输出给其他的RTMP服务器,以SRS转发给SRS为例:
    1. 主SRS:Master,编码器推流到主SRS,主SRS将流处理的同时,将流转发到备SRS。
    2. 备SRS:Slave,主SRS转发流到备SRS,就像编码器推送流到备⽤SRS⼀样。
    3. 测试部署的实例中,主SRS侦听1935端⼝,备SRS侦听19350和19351端⼝。

1. 编写主SRS配置⽂件

  1. vim conf/forward.master.conf
# the config for srs to forward
# @see https://github.com/ossrs/srs/wiki/v1_CN_SampleForward
# @see full.conf for detail config.

listen              1935;
max_connections     1000;
pid                 ./objs/srs.master.pid;
vhost __defaultVhost__ {
    forward {
        enabled on;
        destination 127.0.0.1:19350 127.0.0.1:19351; #forward目的地址,增加一个19351端口
    }
}
  1. 启动srs服务器。
./objs/srs -c conf/forward.master.conf

监听日志信息:tail -f ./objs/srs.log

2. 编写从SRS配置文件

  1. 复制conf/forward.slave.conf到conf/forward.slave1.conf,conf/forward.slave2.conf。
cp conf/forward.slave.conf conf/forward.slave1.conf
cp conf/forward.slave.conf conf/forward.slave2.conf
  1. 修改conf/forward.slave1.conf配置文件。
# the config for srs to forward
# @see https://github.com/ossrs/srs/wiki/v1_CN_SampleForward
# @see full.conf for detail config.

listen              19350; #注意端口
max_connections     1000;
pid                 ./objs/srs.slave1.pid;  #./objs/srs.slave.pid改为./objs/srs.slave1.pid
srs_log_tank 		file;
srs_log_file 		./objs/srs.slave1.log;
vhost __defaultVhost__ {
}
  1. 修改conf/forward.slave2.conf配置文件。
# the config for srs to forward
# @see https://github.com/ossrs/srs/wiki/v1_CN_SampleForward
# @see full.conf for detail config.

listen              19351;
max_connections     1000;
pid                 ./objs/srs.slave2.pid;
srs_log_tank 		file;
srs_log_file 		./objs/srs.slave2.log;
vhost __defaultVhost__ {
}
  1. 启动slave1和slave2
./objs/srs -c conf/forward.slave1.conf
./objs/srs -c conf/forward.slave2.conf


监听日志信息:tail -f ./objs/srs.log
  1. 启动srs后查看srs是否启动成功:netstat -anp|grep srs

3. 验证是否部署成功

1. 启动推流编码器
  1. 使用FFmpeg进行推流
ffmpeg -re -i source.200kbps.768x320.flv -vcodec copy -acodec copy -f flv -y rtmp://8.141.75.248/live/livestream
  1. 涉及到的流包括:
编码器推送的流:rtmp://8.141.75.248/live/livestream

主SRS转发的流:rtmp://8.141.75.248:19350/live/livestream
主SRS转发的流:rtmp://8.141.75.248:19351/live/livestream

观看主SRS的流:rtmp://8.141.75.248/live/livestream
观看从1 SRS的流:rtmp://8.141.75.248:19350/live/livestream
观看从2 SRS的流:rtmp://8.141.75.248:19351/live/livestream
2. 观看主从SRS的RTMP流
  1. 主RTMP流地址为:rtmp://8.141.75.248/live/livestream
  2. 从1 SRS的流:rtmp://8.141.75.248:19350/live/livestream
  3. 从2 SRS的流:rtmp://8.141.75.248:19351/live/livestream
  4. 可以使用VLC观看或者SRS播放器播放:srs播放器
  5. 注意:19350和19351端口需要在服务器开放,不然从节点无法拉流

3. Forward集群源码分析

  1. 从原理上来分析,要实现forward功能:
    1. 读取配置⽂件获取forward server的地址
    2. 创建RTMP推流客户端
    3. 从source⾥⾯拉取消息,然后推送给forward server

1. 从配置文件开始分析

  1. 打开 conf/forward.master.conf 配置文件。
listen              1935;
max_connections     1000;
pid                 ./objs/srs.master.pid;
srs_log_tank        file;
srs_log_file        ./objs/srs.master.log;
vhost __defaultVhost__ {
    forward {
        enabled on;
        destination 127.0.0.1:19350 127.0.0.1:19351;
    }
}

日志打印在终端设置方法:
#srs_log_tank        file;
#srs_log_file        ./objs/srs.log;
daemon              off;
srs_log_tank        console;
  1. 在srs_app_config.cpp中搜索“forward”即可发现读取“forward”的代码。
bool SrsConfig::get_forward_enabled(string vhost)
{
    static bool DEFAULT = false;
    
    SrsConfDirective* conf = get_vhost(vhost);
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("forward");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("enabled");
    if (!conf || conf->arg0().empty()) {
        return DEFAULT;
    }
    
    return SRS_CONF_PERFER_FALSE(conf->arg0());
}

SrsConfDirective* SrsConfig::get_forwards(string vhost)
{
    SrsConfDirective* conf = get_vhost(vhost);
    if (!conf) {
        return NULL;
    }
    
    conf = conf->get("forward");
    if (!conf) {
        return NULL;
    }
    
    return conf->get("destination");
}

2. 使用gdb打断点进行分析:

  1. 使用gdb打断点进行分析:
gdb ./objs/srs

(gdb) set args -c conf/forward.master.conf
(gdb) b SrsConfig::get_forward_enabled(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
Breakpoint 1 at 0x53701d: file src/app/srs_app_config.cpp, line 4837.
(gdb) b SrsConfig::get_forwards(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
Breakpoint 2 at 0x5372df: file src/app/srs_app_config.cpp, line 4859.
  1. 推流后才能进行调试:
ffmpeg -re -i source.200kbps.768x320.flv -vcodec copy -acodec copy -f flv -y rtmp://8.141.75.248/live/livestream
  1. SrsConfig::get_forward_enabled 对应调试信息:
Breakpoint 1, SrsConfig::get_forward_enabled (this=0xa0fcf0, vhost="__defaultVhost__") at src/app/srs_app_config.cpp:4837
4837	{
(gdb) bt
#0  SrsConfig::get_forward_enabled (this=0xa0fcf0, vhost="__defaultVhost__") at src/app/srs_app_config.cpp:4837
#1  0x00000000004e277a in SrsOriginHub::create_forwarders (this=0xab8000) at src/app/srs_app_source.cpp:1467
#2  0x00000000004e1214 in SrsOriginHub::on_publish (this=0xab8000) at src/app/srs_app_source.cpp:1120
#3  0x00000000004e76ce in SrsSource::on_publish (this=0xab7cd0) at src/app/srs_app_source.cpp:2457
#4  0x00000000004d96ca in SrsRtmpConn::acquire_publish (this=0xa9be50, source=0xab7cd0) at src/app/srs_app_rtmp_conn.cpp:940
#5  0x00000000004d874c in SrsRtmpConn::publishing (this=0xa9be50, source=0xab7cd0) at src/app/srs_app_rtmp_conn.cpp:822
#6  0x00000000004d5ee7 in SrsRtmpConn::stream_service_cycle (this=0xa9be50) at src/app/srs_app_rtmp_conn.cpp:534
#7  0x00000000004d4ddf in SrsRtmpConn::service_cycle (this=0xa9be50) at src/app/srs_app_rtmp_conn.cpp:388
#8  0x00000000004d3ba7 in SrsRtmpConn::do_cycle (this=0xa9be50) at src/app/srs_app_rtmp_conn.cpp:209
#9  0x00000000004d1d99 in SrsConnection::cycle (this=0xa9bec8) at src/app/srs_app_conn.cpp:171
#10 0x000000000050ab08 in SrsSTCoroutine::cycle (this=0xa9c130) at src/app/srs_app_st.cpp:198
#11 0x000000000050ab7d in SrsSTCoroutine::pfn (arg=0xa9c130) at src/app/srs_app_st.cpp:213
#12 0x00000000005bed1a in _st_thread_main () at sched.c:337
#13 0x00000000005bf492 in st_thread_create (start=0x5be696 <_st_vp_schedule+170>, arg=0x700000001, joinable=1, stk_size=1) at sched.c:616
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
  1. forward metadata,video,audio数据。
b SrsForwarder::on_meta_data(SrsSharedPtrMessage*)

(gdb) bt
#0  SrsForwarder::on_meta_data (this=0xab9e60, shared_metadata=0xb28490) at src/app/srs_app_forward.cpp:114
#1  0x00000000004df741 in SrsOriginHub::on_meta_data (this=0xab8000, shared_metadata=0xb28490, packet=0xb283f0) at src/app/srs_app_source.cpp:924
#2  0x00000000004e5e23 in SrsSource::on_meta_data (this=0xab7cd0, msg=0xb28210, metadata=0xb283f0) at src/app/srs_app_source.cpp:2113
#3  0x00000000004d9e93 in SrsRtmpConn::process_publish_message (this=0xa9be50, source=0xab7cd0, msg=0xb28210) at src/app/srs_app_rtmp_conn.cpp:1045
#4  0x00000000004d9aa6 in SrsRtmpConn::handle_publish_message (this=0xa9be50, source=0xab7cd0, msg=0xb28210) at src/app/srs_app_rtmp_conn.cpp:993
#5  0x0000000000582720 in SrsPublishRecvThread::consume (this=0xab6480, msg=0xb28210) at src/app/srs_app_recv_thread.cpp:389
#6  0x000000000058123e in SrsRecvThread::do_cycle (this=0xab6488) at src/app/srs_app_recv_thread.cpp:146
#7  0x000000000058108f in SrsRecvThread::cycle (this=0xab6488) at src/app/srs_app_recv_thread.cpp:115
#8  0x000000000050ab08 in SrsSTCoroutine::cycle (this=0xb024f0) at src/app/srs_app_st.cpp:198
#9  0x000000000050ab7d in SrsSTCoroutine::pfn (arg=0xb024f0) at src/app/srs_app_st.cpp:213
#10 0x00000000005bed1a in _st_thread_main () at sched.c:337
#11 0x00000000005bf492 in st_thread_create (start=0xab8290, arg=0xab61b0, joinable=0, stk_size=11231648) at sched.c:616
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
b SrsForwarder::on_video(SrsSharedPtrMessage*)
    
(gdb) bt
#0  SrsForwarder::on_video (this=0xab9e60, shared_video=0xb13080) at src/app/srs_app_forward.cpp:155
#1  0x00000000004e1037 in SrsOriginHub::on_video (this=0xab8000, shared_video=0xb13080, is_sequence_header=true) at src/app/srs_app_source.cpp:1106
#2  0x00000000004e6c59 in SrsSource::on_video_imp (this=0xab7cd0, msg=0xb13080) at src/app/srs_app_source.cpp:2303
#3  0x00000000004e68ad in SrsSource::on_video (this=0xab7cd0, shared_video=0xb28210) at src/app/srs_app_source.cpp:2258
#4  0x00000000004d9c7f in SrsRtmpConn::process_publish_message (this=0xa9be50, source=0xab7cd0, msg=0xb28210) at src/app/srs_app_rtmp_conn.cpp:1021
#5  0x00000000004d9aa6 in SrsRtmpConn::handle_publish_message (this=0xa9be50, source=0xab7cd0, msg=0xb28210) at src/app/srs_app_rtmp_conn.cpp:993
#6  0x0000000000582720 in SrsPublishRecvThread::consume (this=0xab6480, msg=0xb28210) at src/app/srs_app_recv_thread.cpp:389
#7  0x000000000058123e in SrsRecvThread::do_cycle (this=0xab6488) at src/app/srs_app_recv_thread.cpp:146
#8  0x000000000058108f in SrsRecvThread::cycle (this=0xab6488) at src/app/srs_app_recv_thread.cpp:115
#9  0x000000000050ab08 in SrsSTCoroutine::cycle (this=0xb024f0) at src/app/srs_app_st.cpp:198
#10 0x000000000050ab7d in SrsSTCoroutine::pfn (arg=0xb024f0) at src/app/srs_app_st.cpp:213
#11 0x00000000005bed1a in _st_thread_main () at sched.c:337
#12 0x00000000005bf492 in st_thread_create (start=0xab8290, arg=0xab61b0, joinable=0, stk_size=11231648) at sched.c:616
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
b SrsForwarder::on_audio(SrsSharedPtrMessage*)
    
(gdb) bt
#0  SrsForwarder::on_audio (this=0xab9e60, shared_audio=0xb13090) at src/app/srs_app_forward.cpp:132
#1  0x00000000004e02d9 in SrsOriginHub::on_audio (this=0xab8000, shared_audio=0xb13090) at src/app/srs_app_source.cpp:1013
#2  0x00000000004e644e in SrsSource::on_audio_imp (this=0xab7cd0, msg=0xb13090) at src/app/srs_app_source.cpp:2188
#3  0x00000000004e6051 in SrsSource::on_audio (this=0xab7cd0, shared_audio=0xb28210) at src/app/srs_app_source.cpp:2138
#4  0x00000000004d9c00 in SrsRtmpConn::process_publish_message (this=0xa9be50, source=0xab7cd0, msg=0xb28210) at src/app/srs_app_rtmp_conn.cpp:1014
#5  0x00000000004d9aa6 in SrsRtmpConn::handle_publish_message (this=0xa9be50, source=0xab7cd0, msg=0xb28210) at src/app/srs_app_rtmp_conn.cpp:993
#6  0x0000000000582720 in SrsPublishRecvThread::consume (this=0xab6480, msg=0xb28210) at src/app/srs_app_recv_thread.cpp:389
#7  0x000000000058123e in SrsRecvThread::do_cycle (this=0xab6488) at src/app/srs_app_recv_thread.cpp:146
#8  0x000000000058108f in SrsRecvThread::cycle (this=0xab6488) at src/app/srs_app_recv_thread.cpp:115
#9  0x000000000050ab08 in SrsSTCoroutine::cycle (this=0xb024f0) at src/app/srs_app_st.cpp:198
#10 0x000000000050ab7d in SrsSTCoroutine::pfn (arg=0xb024f0) at src/app/srs_app_st.cpp:213
#11 0x00000000005bed1a in _st_thread_main () at sched.c:337
#12 0x00000000005bf492 in st_thread_create (start=0xab8290, arg=0xab61b0, joinable=0, stk_size=11231648) at sched.c:616
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
  1. SrsForwarder::do_cycle() 完成建联,推流到slave操作。
    1. 主要逻辑在:SrsForwarder::forward()
b SrsForwarder::forward()

(gdb) bt
#0  SrsForwarder::forward (this=0xab9e60) at src/app/srs_app_forward.cpp:248
#1  0x00000000004f8648 in SrsForwarder::do_cycle (this=0xab9e60) at src/app/srs_app_forward.cpp:237
#2  0x00000000004f7fd7 in SrsForwarder::cycle (this=0xab9e60) at src/app/srs_app_forward.cpp:190
#3  0x000000000050ab08 in SrsSTCoroutine::cycle (this=0xab9c20) at src/app/srs_app_st.cpp:198
#4  0x000000000050ab7d in SrsSTCoroutine::pfn (arg=0xab9c20) at src/app/srs_app_st.cpp:213
#5  0x00000000005bed1a in _st_thread_main () at sched.c:337
#6  0x00000000005bf492 in st_thread_create (start=0xab8290, arg=0xab61b0, joinable=0, stk_size=11231648) at sched.c:616
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
  1. 后续会补充更详细的代码分析和流程图,现在先自行根据调用stack看源码。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 搭建流媒体服务器需要以下步骤: 1. 安装Linux操作系统,建议使用Ubuntu或CentOS等常见的Linux发行版。 2. 安装流媒体服务器软件,常用的有Nginx-rtmp、Wowza、Red5等。其中,Nginx-rtmp是一个轻量级的流媒体服务器,安装简单,配置灵活,适合小型的流媒体应用;Wowza和Red5则是功能更为强大的流媒体服务器,支持更多的协议和功能。 3. 配置流媒体服务器,包括设置端口、协议、编码格式、流媒体文件存储路径等。 4. 配置流媒体客户端,如VLC、FFmpeg等,以便能够与流媒体服务器进行通信。 5. 测试流媒体服务器,可以使用本地文件或网络摄像头等设备进行测试,确保流媒体服务器正常工作。 总之,搭建流媒体服务器需要一定的技术水平和经验,建议在实践前先学习相关的知识和技术。 ### 回答2: 流媒体服务器是指一个服务器能够接收、编码、存储、和分发流媒体内容的服务器。Linux系统在搭建流媒体服务器上拥有很大优势,因为它拥有从Linux社区和开源社区获得的强大工具箱。在本文中,我们将探讨如何在Linux上搭建流媒体服务器。 第一步:安装Linux操作系统 在搭建流媒体服务器之前,我们需要先选择一个Linux操作系统。我们可以选择稳定,经过良好测试的Debian或者Ubuntu操作系统,也可以选择其他的开源操作系统。然后,我们需要执行以下步骤: 1.安装操作系统。你可以通过官方网站下载需要的系统镜像。 2.在安装过程中设置管理员的用户名和密码。 3.在安装过程中选择安装需要的软件和服务。 第二步:安装LAMP 拥有一个互联网流媒体服务器需要安装一个完整的LAMP(Linux操作系统,Apache HTTP服务,MySQL数据库,以及PHP编程语言)服务集合。在此我们将重点介绍如何搭建Apache服务以及与之相关的一些服务。 1.安装Apache服务器。你可以使用包管理工具apt或dnf来安装。 2.安装MySQL组件。MySQL允许我们在Linux操作系统上运行和存储数据库。 3.安装PHP组件。PHP是用于Web开发的编程语言,在架设流媒体服务器上有很大的用处。 第三步:安装流媒体软件 完成了第二步之后,我们现在需要安装一些流媒体服务软件。这些软件可以帮助我们在Linux操作系统上运行一个实时流媒体服务器。 1.安装Icecast。Icecast是一个开源项目,用于流媒体服务器的基础服务。 2.安装DarkIce。这是一个广泛被流媒体服务器系统使用的基础编码器。 第四步:配置流媒体软件 在安装完所需组件之后,我们需要对它们进行配置,以便流媒体服务器能够顺利的工作。下一步我们将讲述这个操作示例。 1.配置icecast。Icecast的配置文件在”/etc/icecast.xml”目录下,需要在此修改后进行保存。 2.配置DarkIce。配置DarkIce的方法可以参考相关文档等。 第五步:故障排除和调试 最后,我们需要对流媒体服务器进行故障排除和调试。如果你遇到了问题或问题无法解决,可以通过查询问题的错误日志来查出问题所在。这些错误日志可以在”/var/log或/srv/jellies目录下找到。 总结: 以上就是用Linux安装搭建流媒体服务器的大致程。这个程包括安装操作系统、安装LAMP、安装流媒体软件、配置流媒体软件以及故障排查等工作。需要注意的是,这些过程可能因系统版本、软件版本等影响而有所不同。因此,请仔细查阅官方文档以及相关技术博客。最后,总结一下,Linux作为开源操作系统在流媒体服务器架设上有着良好的使用体验,它对于高可靠性、高安全性处理有着卓越的表现,值得我们进一步挖掘和使用。 ### 回答3: Linux是一个开放源代码的内核,它可以为用户提供自由、强大和高度安全的操作系统。通过Linux,我们可以轻松地搭建一个高效的流媒体服务器,用于实时广播音频和视频内容。 搭建流媒体服务器的第一步是安装Linux操作系统。现在市场上有很多不同的发行版可以选择,比如Ubuntu、CentOS、Debian等等。在选择系统的同时,我们还需要确保网络配置以及系统更新等步骤完成。 接下来,我们需要安装流媒体服务器软件。我们可以选择一些行的免费软件,比如FFmpeg、VLC或者Nginx。在这里我们以Nginx作为例子进行讲解。 Nginx是一款非常行的服务器软件,它可以用来处理HTTP和其他网络协议。在流媒体方面,Nginx的优势在于可以快速地向多个客户端播放视频和音频。 安装Nginx非常简单,首先要做的就是打开终端,输入以下命令: sudo apt-get install nginx 安装完成后,我们需要配置Nginx的流媒体服务。 第一步是创建一个RTMP块,在这里我们将定义一些RTMP流媒体的设置。打开配置文件并添加以下内容: rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; } } } 其中,listen指定RTMP服务器监听的端口号,chunk_size定义信息块的大小,live表示开启直播功能,record表示关闭录制功能。 接下来,我们需要设置Nginx服务来支持MP4格式的视频。在server块中添加以下内容: location /videos { mp4; mp4_buffer_size 1m; mp4_max_buffer_size 5m; alias /var/www/html/videos/; } 其中,mp4表明本段服务支持MP4格式的视频,mp4_buffer_size和mp4_max_buffer_size用来设置视频缓冲区的大小,alias用来设置文件夹路径,即视频文件夹的路径。 完成以上配置后,我们需要重新加载Nginx服务以应用新的设置。在终端输入以下命令: sudo service nginx reload 这样就完成了一个流媒体服务器的搭建。现在,我们只需要将我们的音频或视频内容上传到/var/www/html/videos/文件夹中,即可通过RTMP块和MP4服务向多个用户提供实时流媒体内容。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值