Linux下简单的网络编程

43 篇文章 4 订阅
   
    计算机网络是通过通信线路互相连接的计算机的集合,它是由计算机及外围设备、数据通信和中断设备等构成的一个群体。
    TCP/IP协议是Internet上使用的协议,而Internet是世界上最大的计算机网络。
    国际标准化组织ISO对网络标准提出了OSI参考模型,该模型规范了计算机网络的设计并解决了TCP/IP协议没有涉及的底层实现问题。
    Linux系统的一个主要特点是它的网络功能非常强大。随着网络的日益普及,基于网络的应用也将越来越多。

一、计算机网络的组成:
    物理层面上,计算机网络由计算机设备、网络连接设备、传输介质这3个部分组成;
    逻辑层面上,计算机网络由网络协议、网络应用软件、数据这3个部分组成。
    计算机网络根据其组成的形式又可分为多种结构,有的结构适用于某种环境,但更多情况是将多种网络结构复合使用组成实际的网络。
    为了规范不同的计算机和计算机网络进行通信,通常用网络模型来描述需要解决问题的层次,并以网络模型为基础编制出了多种网络传输协议。

    (1).网络结构
    大多数的计算机网络是局域网,整个网络位于一幢建筑物或一个房间内。局域网用于在多台计算机之间共享资源。例如,连接两台计算机和一台打印机的局域网允许任何一台计算机访问打印机,如图所示。

    根据局域网的组成形式,局域网分为星型网络、环状网络和总线网络3种基本网络结构。
    计算机都连在一个中心站点上,那么该网络即是星型网络。星型网络像车轮的轮辐,所以星型网络的中心通常被称为集线器或交换机。典型的集线器或交换机包括了这样一种电子装置,它从发送计算机接收数据并把数据传输到合适的目的地,如图所示。

    环状网络将计算机连接成一个封闭的圆环,一根电缆连接第一台计算机与第二台计算机,另一根电缆连接第二台计算机与第三台,依次类推,直到一根电缆连接最后一台计算机与第一台计算机,如图所示。

    总线网络通常有一根连接计算机的长电缆,任何连接在总线上的计算机都能通过总线发送信号,并且所有计算机也都能接收信号。由于所有连接在电缆上的计算机都能检测到电子信号,因此任何计算机都能向其它计算机发送数据,如图所示。

    每种网络结构都有优点与缺点。
    环状网络使计算机容易协调使用以及容易检测网络是否正确运行。但如果其中两根电缆断掉,整个环状网络都要失效。
    星型网络能保护网络不受某一根电缆损坏的影响,因为每根电缆只连接一台机器。
    总线网络所需的布线比星型网络少,但是有和环状网络一样的缺点。
    所以,对于某一个小的区间来说,网络的实现可能是以上任何一种,但对于大型网络来说,通常是由这3种网络组成的复合结构。

    (2).OSI参考模型
    国际标准化组织开发了开放式系统互联参考模型,以促进计算机系统的开放互联。开放式互联特点是支持不同系统环境互联。该模型为计算机间开放式通信所需要定义的功能层次建立了全球标准。

   该模型的层次依次为:

    物理层:物理层并非是指网络硬件或传输媒介,它只存在于抽象结构中,是负责数据流传输的最底层功能模块。物理层从第二层数据链路层(DDL)接收数据帧,然后以串行方式发送数据帧,每次只发送一个字节。另外,它也负责接收数据流,然后组合成数据帧传送给数据链路层。
    数据链路层:数据链路层的作用是将数据流打包成数据帧,然后将数据帧交给物理层进行传递。也从物理层接收数据帧,并通过循环校验来检测数据传输的可靠性。
    网络层:网络层用于设备间建立路由,处理数据帧中的地址信息。但是,网络层不检验数据的完整性,而是交由数据链路层完成。
    传输层:传输层是以数据包和网段为对象的数据处理层,它是高度抽象化的数据链路层服务。传输层对数据的完整性负责,如果某一数据包丢失,它将要求对方重新发送该数据包。
    会话层:会话层用于建立两个网络终端间的联系,与传输层关系极为密切,用于决定通信的模式是单工还是双工,以及基本的握手协议。
    表示层:表示层用于处理不同计算机的数据编码方式,负责对数据编码进行转换。不同计算机的数据编码系统可能有差别,例如IBMAPPLE系统之间的差别。
    应用层:应用层不包括任何应用,只是为OSI参考模型提供接口。通常,网络协议被应用程序调用的是应用层。

    (3).TCP/IP参考模型
    OSI参考模型并非实际应用中的标准,而只是一种抽象化表示方法。目前真正被广泛使用的是TCP/IP参考模型,它是以OSI参考模型作为基础设计的。Internet的高速发展使TCP/IP参考模型被所有计算机所使用。
    TCP/IP协议是一个协议集,其核心为TCP协议与IP协议。TCP/IP参考模型也是一个开放模型,能适用互联网等各种网络的需要,它具有如下4个特点。
    TCP/IP是一种标准化的高级协议,同时提供了多种网络服务协议。
    完善的网络地址分配方法,网络中每个点都具备独立的地址。
    非专利技术,与操作系统及硬件结构无关。
    与网络硬件无关,适合于各种网络结构。
    TCP/IP参考模型有4个层次。其中应用层与OSI中的应用层对应,传输层与OSI中的传输层对应,网络层与OSI中的网络层对应,物理链路层与OSI中的物理层和数据链路层对应。TCP/IP中没有OSI中的表示层和会话层,如图所示。

    1).应用层
    应用层是TCP/IP参考模型的最高层,它向用户提供一些常用应用程序,如电子邮件等。应用层包括了所有的高层协议,并且总是不断有新的协议加入。应用层协议主要有:网络终端协议TELNET,用于实现互联网中的远程登录功能;文件传输协议FTP,用于实现互联网中交互式文件传输功能;简单电子邮件协议SMTP,实现互联网中电子邮件发送功能;域名服务DNS,用于实现网络设备名字到IP地址映射的网络服务;网络文件系统NFS,用于网络中不同主机间的文件系统共享。
    2).传输层
    传输层也称为TCP层,主要功能是负责应用进程之间的端-端通信。传输层定义了两种协议:传输控制协议TCP与用户数据包协议UDPTCP协议是一种可靠的面向连接的协议,主要功能是保证信息无差错地传输到目的主机。UDP协议是一种不可靠的无连接协议,它与TCP协议不同的是它不进行分组顺序的检查和差错控制,而是把这些工作交给上一级应用层完成。
    3).网络层
    网络层又称为IP层,负责处理互联网中计算机之间的通信,向传输层提供统一的数据包。它的主要功能有以下3个方面:处理来自传输层的分组发送请求;处理接收的数据包;处理互联的路径。
    4).物理链路层
    物理链路层主要功能是接收IP层的IP数据包,通过网络向外发送,或接收处理从网络上传送来的物理帧,抽出IP数据包,向IP层发送。该层是主机与网络的实际连接层。

    TCP/IP协议(Transmission ControlProtocol/Internet Protocol)是随着Internet而发展的网络协议,目前应用最为广泛。Internet最初是因为美国国防需要而建立的,用于保证美国政府的计算机网络间能够互通,并保证遭受核打击时不至于瘫痪。
    TCP/IP很好地解决了不同网络互访问性和网路的健全性,领导着Internet发展。几乎所有的操作系统都支持TCP/IP协议,Linux系统更是将TCP/IP协议作为重要标准,成为了世界上最流行的网络服务器操作系统。

    计算机网络技术在近50年的发展路程中,产生过多种不同的网络结构和通信协议,很多至今还在使用。
    让不同网络可相互访问的结局方案有两种:第一种是选择一种组网络结构为标准,使所有网络都按照同一方法来组建。这种方案显然没有可行性,因为不但网络重建的费用太高,而且没有一种网络结构能满足所有应用。 
    因此,第二种方法被提出,该方法要求设计一种协议,能够让所有网络结构都能支持。TCP/IP协议由此诞生,解决网络互通问题的是IP协议。
    IP协议又称为网际协议,对应于TCP/IP参考模型的网络层,是Internet中最重要的协议。IP协议规定数据包由数据包正文与报头两部分组成。数据包正文是要传递的数据,没有格式要求。报头包括发送主机的网络地址、接收主机的网络地址、数据包的报头校验和、数据包的长度信息。
    IP协议的主要功能有数据包传输、数据包路由选择和拥塞控制。数据包采用“无连接”方式传递,即两台主机在通信之前不需要建立连接。网络主机间使用统一的IP数据包,这样能保持不同物理网络间能够传递和识别数据。如果目的地为同一网段的计算机,那么数据包将被直接传输过去。如果两台主机处于Internet上的不同子网中,IP协议将通过路由器获得主机间的传输路径,通过交换机或服务器接力的方式,将数据包传递过去。
路由器是网络中选择路径的专用计算机,它以图算法为核心,负责找到两点之间最短的距离。同时也会考虑网络的拥堵状况,找到实际最快的传输路径。一些比较大的数据被拆分为数据包后,很可能是以不同的路径传递到目的地。

     IP互联网协议地址
     所有Internet上的计算机都必须有一个Internet上唯一的编号作为其网络标识,这个编号称为IP地址。每个数据包中包含有发送方的IP地址和接收方的IP地址。IP地址是一个32位二进制数,即4个字节,为方便起见,通常将其表示为w.x.y.z的形式。其中,wxyz分别为一个0255的十进制整数,对应二进制表示法中的一个字节。这样的表示叫做点分十进制表示。
nIP地址的取得方式,简单地说是大的组织先向InternetNICNetwork Information Center)申请若干IP地址,然后将其向下级组织分配,下级组织再向更下一级的组织分配IP地址。各子网的网络管理员将取得的IP地址指定给子网中的各台计算机。IP地址分为3类。
    1A类地址
    AIP地址的最高位为0,其前8位为网络地址,是在申请地址时由管理机构设定的,后24位为主机地址,可以由网络管理员分配给本机构子网的各主机。A类地址的第一个十进制整数的值在1126之间。一个A类地址最多可容纳224(约1600万)台主机,最多可有127A类地址。当然这是纯从数学上讲的,事实上不可能达到,因为一个网络中有些地址另有特殊用途,不能分配给具体的主机和网络。下面在B类、C类地址中的数字也是同样的。
    2B类地址
    BIP地址的前16位为网络地址,后16位为主机地址,且第一位为1,第二位为0B类地址的第一个十进制整数的值在128191之间。一个B类网络最多可容纳21665536台主机,最多可有214B类地址。
    3C类地址
    CIP地址的前24位为网络地址,最后8位为主机地址,且第一位、第二位为1,第三位为0C类地址的第一个整数值在192223之间。一个C类网络最多可容纳28256台主机,共有221C类地址。
    有几个特殊的IP地址,第一个是回送地址,该地址用于网络测试或本机进程间通信,十进制形式为127.0.0.1。第二个是广播地址,用于呼叫整个网络内的计算机,子网中最后一个地址即被用作广播地址,例如16.255.255.255用于A类网络16.0.0.0中所有计算机的呼叫。第三个是子网地址,用于识别子网,子网中第一个地址即是子网地址,例如192.168.0.0

    原始互联网使用的传输介质为电话线,计算机通过调制解调器将数值信号转为模拟信号,然后使用电流载波。因为电话线的噪声极大,很容易造成误码,因此TCP协议具有完善的循环校验机制。
    TCP是重要的传输层协议,必须保证数据传递的完整性。另外,数据包报文中有计算机端口号信息,可以用来区别同一计算机上不同应用程序的数据。
    数据包是很小的数据单位,而通过网络传递的连续数据往往是数据包长度的很多倍。因此,数据包报文中还有一个顺序编号,使接收的计算机能够根据编号重新按顺序还原数据。TCP协议的另一个重要功能就是把大的数据切成较小的数据包,或者将接收到的数据包按顺序还原为原始数据。如果发现某一个数据包丢失了,TCP协议会向源计算机发送请求,要求重新传递丢失的数据包。这种处理能力,被称之为全双工。
    TCP 协议最小的处理单位为字节,因此 TCP 是面向字节的顺序协议。数据包内的每个字节都会被分配一个顺序编号,以及为了验证数据真实性的奇偶校验位。虽然这种做法传递了过多的冗余数据,但根本原因是由早期网络极为不可靠造成的。
    为可靠地完成数据传输任务, TCP 将报文或数据分成可管理的长度并加上 TCP 头,并定义一些主要的字段,如图所示。


    TCP 报文中的字段定义如下。
    源端口:源计算机指定的端口编号。
    目的地端口:接收计算机的端口编号。
    顺序号:分配给 TCP 包的编号。
    应答号:接收计算机向源计算机发送的编号。
    偏移位:指出 TCP 头的长度(即 TCP 头中的 32 位字的数)。它表明数据开始和 TCP 头结束。对于正常的 20 字节的头,这个字段设置成 0101
    保留位:为将来使用而保留。必须设置为 0
    控制位:用作个别控制位,如表所示。


    窗口号:窗口字段也称接收窗口大小,表示在 TCP连接上准备由主机接收的8位字节的数目。
    校验位:一个差错检验数,用于确定被接收的数据包文在传输期间是否被讹误。包括TCP头和所有数据。
    紧急指针:它指出了紧接紧急数据的字节的顺序编号。
    可选项:长度变量,它考虑到TCP使用的各种选项:选项表的结束、无操作、最大分段长度。
    TCP提供的主要服务有:

    建立、维持和终结两个进程之间的连接。

    可靠的包传递(经过确认过程)。

    编序包(可靠的数据传送)。

    控制差错的机制。

    通过使用端口,允许在个别的源和目的地主机内部实现和不同进程多重连接的能力。

    使用全双工操作的数据交换。


UDP协议:
    UDP又称用户数据包文协议,也是TCP/IP的传输层协议,它是无连接的、不可靠的传输服务。
当接收数据时它不向发送方提供确认信息,它不提供输入包的顺序。如果出现丢失包或重复包的情况,也不会向发送方发出差错报文,与IP协议非常类似。
    UDP的主要作用是分配和管理端口编号,以正确无误地识别运行在网络站点上的个别应用程序。由于它执行功能时具有低的开销,因而执行速度比TCP快。它多半用于不需要可靠传输的应用程序,例如网络管理域、域名服务器等。


    任何与 UDP 相配合作为传输层服务的应用程序必须提供确认和顺序系统,以确保数据包是以发送时的顺序到达。也就是说,使用 UDP 的应用程序必须提供这类服务。传输层具有独特的、与所有其它层不相关的帧头。 UDP 报头及其数据被封装在 IP 报头内,由 IP 协议将这个数据包文发送到数据链路层,依次下去,数据链路层又使用它的帧头包装这个报文,最后将数据送到物理层实际传输。
    当数据包被接收时,数据链路层将把地址解释为它自己的,剥去它的帧头,将包传递给 IP 层。 IP 层将根据 IP 报头上的正确 IP 地址接受包。剥去它的报头,最后将数据包交给 UDP 软件, UDP 软件接受包必须按 UDP 报头上的端口编号进行译码。

3 .Socket套接字
    Socket 套接字由远景研究规划局( Advanced Research ProjectsAgency, ARPA )资助加利福尼亚大学伯克利分校的一个研究组研发。其目的是将 TCP/IP 协议相关软件移植到 UNIX 类系统中。
    设计者开发了一个接口,以便应用程序能简单地调用该接口通信。这个接口不断完善,最终形成了 Socket 套接字。
    Linux 系统采用了 Socket 套接字,因此, Socket 接口就被广泛使用,到现在已经成为事实上的标准。与套接字相关的函数被包含在头文件 sys/ socket.h 中。
    可见, Socket 的通信机制与电话交换机制非常相似。 Socket 实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。每一个 Socket 都用一个半相关描述。

              {协议,本地地址,本地端口}

    一个完整的 Socket 则用一个相关描述:

            {协议,本地地址,本地端口,远程地址,远程端口}

   每一个 Socket 有一个本地的唯一 Socket 号,由操作系统分配。
    套接字有 3 种类型:流式套接字( SOCK_STREAM )、数据包套接字( SOCK_DGRAM )和原始套接字。
    流式套接字提供可靠的、面向连接的通信流。如果通过流式套接字发送了顺序的数据: 1 2 。那么数据到达远程时候的顺序也是 1 2 。流式套接字可用于 Telnet 远程连接、 WWW 服务等需要使数据顺序传递的应用,它使用 TCP 协议保证数据传输的可靠性。
    流式套接字的工作原理如图所示,网络中的两台主机分别作为服务器和客户机

    数据包套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠性。
    数据包套接字使用数据包协议 UDP ,数据只是简单地传送到对方。
    数据包套接字的工作原理如图所示。


(1).socket套接字的简介
    原始套接字允许对底层协议如 IP ICMP 直接访问,主要用于新的网络协议实现的测试等。
    原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。

(2).创建套接字
    套接字是通过标准的 UNIX 文件描述符和其它的程序通信的一个方法。套接字在使用前必须先被建立,建立套接字的系统调用为 socket() ,它的一般形式是:

      int socket(int domain, int type, int protocol);

    创建出来的套接字是一条通信线路的一个端点,domain参数负责指定地址族,type参数负责指定与这个套接字一起使用的通信类型,而protocol参数负责制定所使用的协议。domain参数的取值范围如表所示。

   
    最常用的套接字是 AF_UNIX AF_INET ,前者用于通过 UNIX 文件系统实现的本地套接字,后者用于 UNIX 网络套接字。
    AF_INET 套接字可以用在穿过包括 Internet 在内的各种 TCP/IP 网络而进行通信的应用程序中。
    参数 type 指定了与新套接字对应的通信特性。它的取值范围为枚举常量 SOCK_STREAM SOCK_DGRAM
    SOCK_STREAM 是一个有序的、可靠的、基于连接的双向字节流。对于一个 AF_INET 域的套接字来说,如果在两个流式套接字的两端之间建立的是一个 TCP 连接,连接时默认值即为该特性。 SOCK_DGRAM 是一个数据报服务,可以用来发送最大长度是一个固定值的消息,但消息是否会被送达或者消息的先后次序是否会在网络传输中被重新安排并没有保证。对于 AF_INET 域的套接字来说,这种类型的通信是由 UDP 提供的。
    通信所用的协议通常是由套接字的类型和套接字的域来决定,如果还有其它的协议可以选择,那么就在 protocol 参数里设置。 protocol 参数默认值为 0 ,表示使用默认的协议。
    socket 系统调用返回的是一个描述符,它与文件描述符非常相似。当这个套接字和通信线路另一端的套接字连接好以后,就可以进行数据的传输和接收操作了。

(3).套接字地址
    每个套接字域都有独特的地址格式。对于一个 AF_UNIX 套接字来说,它的地址是由一个包含在 sys/ un.h 头文件里的 sockaddr_un 结构描述的。该结构的定义为:

       structsockaddr_un

      {

          sa_family_tsun_family;  // AF_UNIX

          char sun_path[];  // 路径

      };

    因为不同类型的地址都需要传递到对套接字进程处理的系统调用里去,所以定义各种地址格式时使用的结构也都很相似,每个结构的开始都是一个定义地址类型(即套接字域)的数据项。 sun_family_t 是由 X/Open 技术规范定义的,在 Linux 系统上,它被声明为一个 short 类型。 sun_path 给出的路径长度是有限制的, Linux 规定其最长不能超过 108 个字符。因为地址结构在长度方面是不固定的,所以许多套接字调用都要用到或输出一个用来复制特定地址结构的长度值。
    AF_INET 域里的套接字地址是由一个定义在 netinet / in.h 头文件里的 sockaddr_in 结构确定的。该结构的定义为:

      structsockaddr_in {

         short intsin_family;   // AF_INET

         unsigned short intsin_port;  // 端口号

         structin_addrsin_addr;   // Internet地址

                                      };

    其中 Internet 地址是 netinet / in.h 头文件中定义的另一个结构体,该结构体的定义为:

          structin_addr {

                unsigned long ints_addr;};

    一个 AF_INET 套接字完全可以由它的域、 IP 地址和端口号确定下来。从应用程序的角度看,各种套接字的行为就像是文件描述符,用一个独一无二的整数就可以把它们表示出来。

(4).套接字的名字
    要使socket()调用创建的套接字能够被其它进程使用,程序就必须给该套接字起个名字。AF_UNIX套接字会关联到一个文件系统的路径名上去,AF_INET套接字将关联到一个IP端口号上去。为套接字命名可使用bind()系统调用,它的一般形式如下:
     int bind(int socket, const structsockaddr*address, size_taddress_len);
    bind()系统调用的作用是把参数address中给出的地址赋值给与文件描述符socket相关联的未命名套接字。地址结构的长度是通过address_len参数传递的。地址的长度和类型取决于地址族。bind()调用需要用一个与之对应的地址结构指针指向真正的地址类型。该调用成功时将返回0,否则返回–1,并将errno变量设置为表中的值。

    AF_UNIX 套接字对应的错误代码比上表要多出两个,分别是 EACCESS ,表示权限不足,不能创建文件系统中使用的名字; ENOTDIR/ENAMETOOLONG ,表示路径错误或路径名太长。

(5).创建套接字队列
    为能够在套接字上接受接入的连接,服务器程序必须创建一个队列来保存到达的请求。创建队列可使用系统调用 listen() 完成,它的一般形式为:

         int listen(int socket, int backlog);

    Linux 系统可能会对队列里能够容纳的排队连接的最大个数有限制。在这个最大值的范围内, listen() 将把队列长度设置为 backlog 个连接。在套接字上排队的接入连接个数最多不能超过这个数字,再往后的连接将被拒绝,用户的连接请求将会失败。这是 listen() 提供的一个机制,在服务器程序紧张地处理着上一个客户的时候,后来的连接将被放到队列里排队等号。 backlog 常用的值是 5
    listen() 函数成功时会返回 0 ,否则返回 –1 ,它的错误代码包括 EBADF EINVAL ENOTSOCK ,含义同 bind() 系统调用的错误代码相同。

(6).接受连接
    服务器上的应用程序创建好命名套接字之后,就可以通过 accept() 系统调用来等待客户端程序建立对该套接字的连接了。    accept() 的一般形式是:

    int accept(int socket, structsockaddr*address, size_t*address_len);

    accept() 系统调用会等到有客户程序试图连接到由 socket 参数指定的套接字时才返回。该客户就是套接字队列里排在第一位的连接。
    accept() 函数将创建出一个 新的套接字 来与该客户进行通信,返回的是与之对应的文件描述符。新套接字的类型与服务器监听套接字的类型相同。

(6).请求连接
    当客户想要连接到服务器的时候,它会尝试在一个未命名套接字和服务器的监听套接字之间建立一个连接。它们用 connect() 系统调用来完成这一工作,它的一般形式是:

    int connect(int socket, const structsockaddr*address, size_taddress_len);

    参数 socket 指定的套接字将连接到参数 address 指定的服务器套接字上去,服务器套接字的长度由参数 address_len 指定。套接字必须是通过 socket 调用获得的一个有效的文件描述符。如果操作成功,函数返回 0 ,否则返回 –1 。该函数产生的错误代码如表所示。

    如果连接不能立刻建立起来, connect() 会阻塞一段不确定的倒计时时间,倒计时结束后,连接就会失败。若 connect() 调用是被信号所中断,且该信号得到了处理, connect 还是会失败,但这次连接尝试是成功的,它会以异步方式继续尝试。
    类似于 accept() 调用, connect() 的阻塞特性可以用设置该文件描述符的 O_NONBLOCK 标志的办法来改变。在这种情况下,如果连接不能立刻建立起来, connect() 会失败并把 errno 变量设置为 EINPROGRESS ,而连接将以异步方式继续尝试。
    异步连接的处理是比较困难的,可以在套接字文件描述符上用一个 select() 调用来表明该套接字已经处于写就绪状态。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

daijingxin

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

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

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

打赏作者

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

抵扣说明:

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

余额充值