C#net6实现Linux系统下修改IP地址、修改系统时间、获取内存信息、获取磁盘信息、重启系统

C#net6实现Linux系统下修改IP地址、修改系统时间、获取内存信息、获取磁盘信息、重启系统

背景

随着微软.net core的出现,C#程序实现跨平台不在困难,5年内微软连续退出.net core 2、.net core 3、net5、net6,到现在net7预览版本,可以发现除了原来WinForm部分,其他大部分的功能都可以通过net6实现跨平台发布。由于其运行效率相比java高出不少,会有越来越道的服务通过net6进行开发。作为工业软件开发者的一员,借助项目需求,就把项目中用到的部分冷门的功能进行整理,进行分享,希望遇到类似问题的小伙伴们少走弯路。

项目背景

本次项目需求是研发一款数字仪表采集器,数字仪表的种类包括数字电表、蒸汽表、温湿度仪表。通讯接口主要是RS485、采集器基于辉为DTU820工控机(操作系统为linux4.x Arm7,512M内存,4G存储。带4路485接口,根据采集频率的要求不同,每路485可以串联多块数字仪表)进行开发。基于开发效率和程序性能的综合考虑决定采用c#基于net6进行开发。系统分为数据采集服务、数据上传服务、终端配置站点三个子程序。因为终端配置站点需要实现修改工控机网卡IP地址,实现从服务器同步时间到工控机等功能。

实现思路

原来在windows下通过C#修改系统时间,是通过调用Win32API实现的,很明显,这种方式的代码无法运行在linux环境下。网上一顿搜索,也没有发现相关资料。因为linux下很多操作都是通过终端命令完成,就想能不能通过C#执行linux终端命令,经过尝试,是可以的。这样很多问题就可以通过这种方式解决了。(注意修改IP地址是通过修改网卡的配置文件实现,其实就是文件操作)现对实现的关键代码进行整理分享如下。

代码实现

用到的3个实体类
DiskInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wongoing.Basic.Entity
{
    /// <summary>
    /// 磁盘信息实体类
    /// </summary>
    [Serializable]
    public class DiskInfo
    {
        #region 字段定义

        private string? _fileSystem;
        private long _size;
        private long _used;
        private long _available;
        private string? _usePercent;
        private string? _mountedOn;

        #endregion

        #region 属性定义

        /// <summary>
        /// 磁盘名称/文件系统
        /// </summary>
        public string? FileSystem { get => _fileSystem; set => _fileSystem = value; }
        /// <summary>
        /// 容量大小
        /// </summary>
        public long Size { get => _size; set => _size = value; }
        /// <summary>
        /// 已用大小
        /// </summary>
        public long Used { get => _used; set => _used = value; }
        /// <summary>
        /// 可用大小
        /// </summary>
        public long Available { get => _available; set => _available = value; }
        /// <summary>
        /// 已用%
        /// </summary>
        public string? UsePercent { get => _usePercent; set => _usePercent = value; }
        /// <summary>
        /// 挂载点
        /// </summary>
        public string? MountedOn { get => _mountedOn; set => _mountedOn = value; }

        /// <summary>
        /// 容量大小(GB)
        /// </summary>
        public double SizeGB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._size / 1024.0 / 1024.0), out result);
                return result;
            }
        }

        /// <summary>
        /// 已用大小(GB)
        /// </summary>
        public double UsedGB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._used / 1024.0 / 1024.0), out result);
                return result;
            }
        }

        /// <summary>
        /// 可用大小(GB)
        /// </summary>
        public double AvailableGB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._available / 1024.0 / 1024.0), out result);
                return result;
            }
        }

        #endregion
    }
}

MemoryInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wongoing.Basic.Entity
{
    /// <summary>
    /// 内存信息实体类
    /// </summary>
    [Serializable]
    public class MemoryInfo
    {
        #region 字段定义

        private long _total;
        private long _used;
        private long _free;
        private long _shared;
        private long _buffers;
        private long _cached;

        #endregion

        #region 属性定义

        /// <summary>
        /// 内存总大小
        /// </summary>
        public long Total { get => _total; set => _total = value; }
        /// <summary>
        /// 已用内存大小
        /// </summary>
        public long Used { get => _used; set => _used = value; }
        /// <summary>
        /// 可用内存大小
        /// </summary>
        public long Free { get => _free; set => _free = value; }
        /// <summary>
        /// 共享内存大小
        /// </summary>
        public long Shared { get => _shared; set => _shared = value; }
        /// <summary>
        /// Buffer缓冲大小
        /// </summary>
        public long Buffers { get => _buffers; set => _buffers = value; }
        /// <summary>
        /// Cache缓存大小
        /// </summary>
        public long Cached { get => _cached; set => _cached = value; }

        /// <summary>
        /// 内存总大小
        /// </summary>
        public double TotalMB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._total / 1024.0), out result);
                return result;
            }
        }

        /// <summary>
        /// 已用内存大小
        /// </summary>
        public double UsedMB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._used / 1024.0), out result);
                return result;
            }
        }

        /// <summary>
        /// 可用内存大小
        /// </summary>
        public double FreeMB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._free / 1024.0), out result);
                return result;
            }
        }

        /// <summary>
        /// 共享内存大小
        /// </summary>
        public double SharedMB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._shared / 1024.0), out result);
                return result;
            }
        }

        /// <summary>
        /// Buffer缓冲大小
        /// </summary>
        public double BuffersMB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._buffers / 1024.0), out result);
                return result;
            }
        }

        /// <summary>
        /// Cache缓存大小
        /// </summary>
        public double CachedMB
        {
            get
            {
                double result = 0.0;
                double.TryParse(String.Format("{0:F2}", this._cached / 1024.0), out result);
                return result;
            }
        }

        #endregion
    }
}

NetworkInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wongoing.Basic.Entity
{
    /// <summary>
    /// 网络信息实体类
    /// </summary>
    [Serializable]
    public class NetworkInfo
    {
        #region 字段定义

        private string _networkCard = "eth0";
        private string _address = "192.168.0.15";
        private string _netmask = "255.255.255.0";
        private string _gateway = "192.168.0.1";

        #endregion

        #region 属性定义

        /// <summary>
        /// 网卡(eth0、eth1)
        /// </summary>
        public string NetworkCard { get => _networkCard; set => _networkCard = value; }
        /// <summary>
        /// IP地址
        /// </summary>
        public string Address { get => _address; set => _address = value; }
        /// <summary>
        /// 子网掩码
        /// </summary>
        public string Netmask { get => _netmask; set => _netmask = value; }
        /// <summary>
        /// 网关
        /// </summary>
        public string Gateway { get => _gateway; set => _gateway = value; }

        #endregion
    }
}

C#调用 Linux终端命令的关键代码如下:
LinuxCommandHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Wongoing.Basic.Linux
{
    /// <summary>
    /// Linux命令工具类
    /// </summary>
    public class LinuxCommandHelper
    {
        private static string FileName { get; set; }
        private static string Arguments { get; set; }
        private static string WorkingDirectory { get; set; }

        /// <summary>
        /// 运行命令
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="arguments"></param>
        /// <param name="workingDirectory"></param>
        /// <returns></returns>
        public static string RunCommand(string fileName, string arguments, string workingDirectory = "")
        {
            FileName = fileName;
            Arguments = arguments;
            WorkingDirectory = workingDirectory;
            return Execute();
        }
        

        private static string Execute(int milliseconds = 10000)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                var rValue = "";
                using (System.Diagnostics.Process p = new System.Diagnostics.Process())
                {
                    p.StartInfo.FileName = FileName;
                    p.StartInfo.Arguments = Arguments;
                    p.StartInfo.UseShellExecute = false;
                    p.StartInfo.RedirectStandardOutput = true;
                    p.StartInfo.WorkingDirectory = WorkingDirectory;
                    p.Start();
                    p.WaitForExit(milliseconds);
                    rValue = p.StandardOutput.ReadToEnd();
                }
                return rValue;
            }
            else
            {
                return "当前系统不是Linux系统,不能通过此类执行Linux命令!";
            }
        }
    }
}

各种操作的封装类LinuxOSHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wongoing.Basic.Linux
{
    using Wongoing.Basic.Entity;

    /// <summary>
    /// linux操作系统基本操作辅助类
    /// </summary>
    public class LinuxOSHelper
    {
        #region 定义常量

        public static readonly string InterfaceTemplate = @"# interface file auto-generated by buildroot

            auto lo
            iface lo inet loopback

            auto eth0
            iface eth0 inet static
            address ${eth0_address}
            netmask ${eth0_netmask}
            gateway ${eth0_gateway}

            auto eth1
            iface eth1 inet static
            address ${eth1_address}
            netmask ${eth1_netmask}
            gateway ${eth1_gateway}
        ";

        #endregion

        #region 获取当前系统内核

        /// <summary>
        /// 获取当前系统内核
        /// </summary>
        /// <returns>返回系统内核信息</returns>
        public static string GetSystemCore()
        {
            string result = LinuxCommandHelper.RunCommand("uname", "-a");
            return result;
        }

        #endregion

        #region 获取系统内存信息

        /// <summary>
        /// 获取系统内存信息
        /// </summary>
        /// <returns>返回系统内存信息</returns>
        public static MemoryInfo GetSystemMemoryInfo()
        {
            string result = LinuxCommandHelper.RunCommand("free", "");
            string? line = String.Empty;
            List<string> valueList = new List<string>();
            using (StringReader reader = new StringReader(result))
            {
                while (!String.IsNullOrEmpty((line = reader.ReadLine())))
                {
                    if (line.StartsWith("Mem:"))
                    {
                        string[] split = line.Split(' ');
                        foreach (string value in split)
                        {
                            if (!String.IsNullOrEmpty(value) && value != "Mem:")
                            {
                                valueList.Add(value);
                            }
                        }
                        break;
                    }
                }
            }
            MemoryInfo memoryInfo = new MemoryInfo();
            long val = 0;
            for (int i = 0; i < valueList.Count; i++)
            {
                if (i == 0)
                {
                    val = 0;
                    long.TryParse(valueList[i], out val);
                    memoryInfo.Total = val;
                }
                if (i == 1)
                {
                    val = 0;
                    long.TryParse(valueList[i], out val);
                    memoryInfo.Used = val;
                }
                if (i == 2)
                {
                    val = 0;
                    long.TryParse(valueList[i], out val);
                    memoryInfo.Free = val;
                }
                if (i == 3)
                {
                    val = 0;
                    long.TryParse(valueList[i], out val);
                    memoryInfo.Shared = val;
                }
                if (i == 4)
                {
                    val = 0;
                    long.TryParse(valueList[i], out val);
                    memoryInfo.Buffers = val;
                }
                if (i == 5)
                {
                    val = 0;
                    long.TryParse(valueList[i], out val);
                    memoryInfo.Cached = val;
                }
            }
            return memoryInfo;
        }

        #endregion

        #region 获取系统磁盘信息

        /// <summary>
        /// 获取系统磁盘信息
        /// </summary>
        /// <returns>返回各分区磁盘信息</returns>
        public static List<DiskInfo> GetSystemDisckInfo()
        {
            string result = LinuxCommandHelper.RunCommand("df", "");
            string? line = String.Empty;
            List<DiskInfo> resultLlist = new List<DiskInfo>();
            DiskInfo? diskInfo = null;
            using (StringReader reader = new StringReader(result))
            {
                while (!String.IsNullOrEmpty((line = reader.ReadLine())))
                {
                    if (line.StartsWith("/dev"))
                    {
                        #region 处理已/dev开头的信息

                        List<string> valueList = new List<string>();
                        string[] split = line.Split(' ');
                        foreach (string value in split)
                        {
                            if (!String.IsNullOrEmpty(value))
                            {
                                valueList.Add(value);
                            }
                        }
                        long val = 0;
                        diskInfo = new DiskInfo();
                        for (int i = 0; i < valueList.Count; i++)
                        {
                            if (i == 0)
                            {
                                diskInfo.FileSystem = valueList[i];
                            }
                            if (i == 1)
                            {
                                val = 0;
                                long.TryParse(valueList[i], out val);
                                diskInfo.Size = val;
                            }
                            if (i == 2)
                            {
                                val = 0;
                                long.TryParse(valueList[i], out val);
                                diskInfo.Used = val;
                            }
                            if (i == 3)
                            {
                                val = 0;
                                long.TryParse(valueList[i], out val);
                                diskInfo.Available = val;
                            }
                            if (i == 4)
                            {
                                diskInfo.UsePercent = valueList[i];
                            }
                            if (i == 5)
                            {
                                diskInfo.MountedOn = valueList[i];
                            }
                        }
                        resultLlist.Add(diskInfo);

                        #endregion
                    }
                }
            }
            return resultLlist;
        }

        #endregion

        #region 生成网络配置文件

        /// <summary>
        /// 生成网络配置文件
        /// </summary>
        /// <param name="eth0">网卡1信息</param>
        /// <param name="eth1">网卡2信息</param>
        /// <returns>返回网络配置文件内容</returns>
        public static string BuildNetworkFileContent(NetworkInfo eth0, NetworkInfo eth1)
        {
            string networkFileContent = InterfaceTemplate;
            if (eth0 == null)
            {
                eth0 = new NetworkInfo() { NetworkCard = "eth0", Address = "192.168.0.15", Netmask = "255.255.255.0", Gateway = "192.168.0.1" };
            }
            if (eth1 == null)
            {
                eth1 = new NetworkInfo() { NetworkCard = "eth1", Address = "10.10.80.15", Netmask = "255.255.255.0", Gateway = "10.10.80.1" };
            }
            Type type = typeof(LinuxOSHelper);
            string interfaceTemplateFilePath = String.Format("{0}.{1}", type.Assembly.GetName().Name, "Resource.interfaces.template.txt");
            System.IO.Stream? stream = type.Assembly.GetManifestResourceStream(interfaceTemplateFilePath);
            if (stream != null)
            {
                System.IO.StreamReader streamReader = new System.IO.StreamReader(stream);
                networkFileContent = streamReader.ReadToEnd();
            }
            networkFileContent = networkFileContent.Replace("${eth0_address}", eth0.Address);
            networkFileContent = networkFileContent.Replace("${eth0_netmask}", eth0.Netmask);
            networkFileContent = networkFileContent.Replace("${eth0_gateway}", eth0.Gateway);

            networkFileContent = networkFileContent.Replace("${eth1_address}", eth1.Address);
            networkFileContent = networkFileContent.Replace("${eth1_netmask}", eth1.Netmask);
            networkFileContent = networkFileContent.Replace("${eth1_gateway}", eth1.Gateway);

            networkFileContent = networkFileContent.Replace("\r", String.Empty);
            networkFileContent = networkFileContent.Replace("            ", String.Empty);

            return networkFileContent;
        }

        #endregion

        #region 获取系统本地时间

        /// <summary>
        /// 获取系统本地时间
        /// </summary>
        /// <returns>返回系统本地时间</returns>
        public static string GetLocaleDateTime()
        {
            string result = LinuxCommandHelper.RunCommand("date", "");
            return result;
        }

        #endregion

        #region 设置系统本地时间

        /// <summary>
        /// 设置系统本地时间
        /// </summary>
        /// <param name="datetimestr">要设置的时间</param>
        /// <returns>返回设置的时间</returns>
        public static string SetLocaleDateTime(string datetimestr)
        {
            string result = LinuxCommandHelper.RunCommand("date", $"-s \"{datetimestr}\"");
            LinuxCommandHelper.RunCommand("hwclock", "-w");
            return result;
        }

        #endregion

        #region 系统立即重启

        /// <summary>
        /// 系统立即重启
        /// </summary>
        /// <returns>返回执行结果</returns>
        public static string RebootNow()
        {
            string result = LinuxCommandHelper.RunCommand("reboot", "now");
            return result;
        }

        #endregion

        #region 系统重启

        /// <summary>
        /// 系统重启
        /// </summary>
        /// <returns>返回执行结果</returns>
        public static string Reboot()
        {
            string result = LinuxCommandHelper.RunCommand("reboot", "");
            return result;
        }

        #endregion
    }
}

OSHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Wongoing.Basic
{
    using System.Net.NetworkInformation;
    using Wongoing.Basic.Entity;
    using Wongoing.Basic.Linux;
    using Wongoing.Basic.Win;
    /// <summary>
    /// 操作系统辅助类
    /// </summary>
    public class OSHelper
    {
        #region 获取当前系统内核

        /// <summary>
        /// 获取当前系统内核
        /// </summary>
        /// <returns>返回系统内核信息</returns>
        public static string GetSystemCore()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return LinuxOSHelper.GetSystemCore();
            }
            else
            {
                return Environment.OSVersion.ToString();
            }
        }

        #endregion

        #region 获取系统内存信息

        /// <summary>
        /// 获取系统内存信息
        /// </summary>
        /// <returns>返回系统内存信息</returns>
        public static MemoryInfo? GetSystemMemoryInfo()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return LinuxOSHelper.GetSystemMemoryInfo();
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region 获取系统磁盘信息

        /// <summary>
        /// 获取系统磁盘信息
        /// </summary>
        /// <returns>返回各分区磁盘信息</returns>
        public static List<DiskInfo> GetSystemDisckInfo()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return LinuxOSHelper.GetSystemDisckInfo();
            }
            else
            {
                return new List<DiskInfo>();
            }
        }

        #endregion

        #region 生成网络配置文件

        /// <summary>
        /// 生成网络配置文件
        /// </summary>
        /// <param name="eth0">网卡1信息</param>
        /// <param name="eth1">网卡2信息</param>
        /// <returns>返回网络配置文件内容</returns>
        public static bool BuildNetworkFileContent(NetworkInfo eth0, NetworkInfo eth1, string fileFullPath)
        {
            try
            {
                string? path = System.IO.Path.GetDirectoryName(fileFullPath.Contains(".") ? fileFullPath : String.Format("{0}.txt", fileFullPath));
                if (path == null)
                {
                    path = "/etc/network";
                }
                if (!System.IO.Directory.Exists(path))
                {
                    System.IO.Directory.CreateDirectory(path);
                }
                string networkFileContent = LinuxOSHelper.BuildNetworkFileContent(eth0, eth1);
                using(System.IO.StreamWriter sw = new System.IO.StreamWriter(fileFullPath))
                {
                    sw.Write(networkFileContent);
                    sw.Flush();
                    sw.Close();
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        #endregion

        #region 获取系统本地时间

        /// <summary>
        /// 获取系统本地时间
        /// </summary>
        /// <returns>返回系统本地时间</returns>
        public static string GetLocaleDateTime()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return LinuxOSHelper.GetLocaleDateTime();
            }
            else
            {
                return String.Format("{0:yyyy-MM-dd HH:mm:ss}", DateTime.Now);
            }
        }

        #endregion

        #region 设置系统本地时间

        /// <summary>
        /// 设置系统本地时间
        /// </summary>
        /// <param name="datetimestr">要设置的时间</param>
        /// <returns>成功则返回生效的时间,失败返回String.Empty</returns>
        public static string SetLocaleDateTime(string datetimestr)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return LinuxOSHelper.SetLocaleDateTime(datetimestr);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                return WinOSHelper.SetLocaleDateTime(datetimestr);
            }
            else
            {
                return String.Empty;
            }
        }

        #endregion

        #region 检测某个IP或域名是否可以Ping通

        /// <summary>
        /// 检测某个IP或域名是否可以Ping通
        /// </summary>
        /// <param name="strIpOrDName">IP或域名</param>
        /// <returns>真为通,假为不同</returns>
        public static bool Ping(string strIpOrDName)
        {
            try
            {
                Ping objPingSender = new Ping();
                PingOptions objPinOptions = new PingOptions();
                objPinOptions.DontFragment = true;
                string data = "";
                byte[] buffer = Encoding.UTF8.GetBytes(data);
                int intTimeout = 120;
                PingReply objPinReply = objPingSender.Send(strIpOrDName, intTimeout, buffer, objPinOptions);
                string strInfo = objPinReply.Status.ToString();
                if (strInfo == "Success")
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        #endregion

        #region 获取IpV4地址列表

        /// <summary>
        /// 获取IpV4地址列表
        /// </summary>
        /// <returns>返回IpV4地址列表</returns>
        public static List<string> GetIpV4AddressList()
        {
            List<string> list = new List<string>();
            string HostName = Dns.GetHostName();
            IPHostEntry ipEntry = Dns.GetHostEntry(HostName);
            for (int i = 0; i < ipEntry.AddressList.Length; i++)
            {
                //从IP地址列表中筛选出IPv4类型的IP地址
                //AddressFamily.InterNetwork表示此IP为IPv4,
                //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                if (ipEntry.AddressList[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    list.Add(ipEntry.AddressList[i].ToString());
                }
            }
            return list;
        }

        #endregion

        #region 更改IP地址

        #endregion

        #region 系统立即重启

        /// <summary>
        /// 系统立即重启
        /// </summary>
        /// <returns>返回执行结果</returns>
        public static string RebootNow()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return LinuxOSHelper.RebootNow();
            }
            else
            {
                return "暂不支持其他操作系统!";
            }
        }

        #endregion

        #region 系统重启

        /// <summary>
        /// 系统重启
        /// </summary>
        /// <returns>返回执行结果</returns>
        public static string Reboot()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return LinuxOSHelper.Reboot();
            }
            else
            {
                return "暂不支持其他操作系统!";
            }
        }

        #endregion
    }
}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值