【Java EE初阶十六】网络原理(一)

这篇具有很好参考价值的文章主要介绍了【Java EE初阶十六】网络原理(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        在网络原理中主要学习TCP/IP四层模型中的重点网络协议

1. 应用层

1.1 应用程序与协议

        应用层是和程序员接触最密切的;

        应用程序:在应用层这里,很多时候都是程序员自定义应用层协议(步骤:1、根据需求,明确要传输的信息,2、约定好信息按照什么样的格式来组织)的;所谓的网络协议其实就是约定,即程序员在代码中规划好,数据如何进行传输;

        下面是自定义协议的例子:

1、点外卖
        点开外卖软件,首先会看到商家列表, 这里就涉及到程序和服务器之间进行的网络通信交互

2、请求: 用户信息, 位置信息,
        此处假设就使用简单的格式来组织,使用文本的方式.三个属性,使用""来分割
1000,100,30()--->代码中构造出一个这样的字符串,给写入到 Tcp socket 或者 Udp 的 socket 中

3、响应: 商家列表(多个商家),每个商家,包含 名称,图片,距离,简介,评分.
        此处假设使用简单的格式来组织,使用文本的方式,每个商家信息占一行,每个属性使用","来分割
过桥米线,图片地址1,1.1km,评分5
张亮麻辣烫,图片地址2,2.3km,评分4.8
魏家凉皮,图片地址3,3km,评分4.9

        上述这个过程,就是自定义协议.针对这里的情况,使用啥样的格式来组织,只要客户端和服务器双方能够对应上都是可以的;

1.2 开发中构造协议的格式

1.2.1 xml

        (通过标签来组织数据)

        早期的组织数据的格式,现在几乎很少用于网络通信,下图是代码展示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

xml 的优势:
        让数据的可读性变的更好;

xml 的劣势:
        标签写起来非常繁琐,传输的时候也占用更多网络带宽,(maven, 就会使用 xml 来管理项目配置)

1.2.2 json

        (当下最流行的一种数据组织格式)

         json格式使用键值对,通过{ }把所有的键值对给包裹起来,键值对之间,使用","来分割,键和值之间,使用 ": ” 来分割,其中键固定就是 string 类型,值的话,可以是数字,可以是字符串,也可以是 json,还可以是数组;由于 json 的 key 固定就是字符串类型,很多时候也是可以把 key 的引号给省略的

        下图是代码展示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

json 的优势:

        可读性比较好的; 比 xml 更简洁.

json 的劣势:        
        同样也是会在网络传输中,消耗额外的带宽 (需要把 key 也进行传输的)

虽然如此,json 在网络通信中仍然非常流行,除非是些对于性能要求非常高的场景,不使用json 之外,其余的很多地方都可以使用 json

1.2.3 protobuffer

        相比于json 和 xml 来说,protobufer (简称为 pb)使用二进制的方式来组织数据,可以保证带宽占用最低(相当于把要传递的信息按照二进制形式压缩了)
pb 的优势:.
        占用带宽最低,传输效率最高.非常适合于对于性能要求比较高的场景,
pb的劣势
        可读性不好(二进制结构,肉眼无法直接阅读),一定程度的影响开发效率,

        应用层中也有一些"现成"的应用层协议,其中最知名的,最广泛使用的,就是 HTTP 协议了(超文本传输协议)~~>“超文本”不仅仅是文本,还有图片,视频,音频,字体.. 

2. 传输层

        传输层中使用到的协议主要有TCP和UDP协议:

        端口号:写一个服务器,必须手动指定一个端口号,通过端口来区分当前这个主机上的不同的应用程用,客户端在通信的时候也会有一个端口号(代码中感受不到),系统自动分配的一个客户端,
        端口号,固定就是占2 个字节.表示的数据范围0->65535,一般来说,0是不用的.其中1-1023 称为"知名端口号,1024-65535 普通的端口号,平时自己写代码,用的端口还是普通的端口号为好一点;

2.1 UDP协议

2.1.1 udp报文格式

        学习一个协议,其中最主要的工作,就是去理解协议报文格式。

        udp协议的报文格式总体如下图所示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        udp协议的报文格式的详细分析图如下图所示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

       源 ip, 目的 ip 不在传输层,而是在网络层 (IP 协议里);像UDP,TCP这样的报文格式,是最初一些大佬们设计并约定出来的内容,最后被整理成了一份标准文档,称为RFC标准文档;

2.1.2 报文案例分析

        用户使用浏览器进行搜索原理如下图所示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        于业务的发展,搜集信息越来越多了,样式也越来越复杂了.导致商搜服务器和入口服务器之间交互的数据量,已经接近 64kb (udp报文长度就是64kb)了.如果超过上限,数据就会出现截断,最终展示在页面上的数据肯定就会出错
        方案一:把数据拆分成多个包,使用多个 UDP 数据报进行传输.(开发成本,比较大)       

        方案二:直接使用 TCP.TCP 没有数据包的大小限制.

2.1.3 关于校验和

         校验和是计算机中非常广泛使用的概念.由于在网络传输中,一些设备被外部干扰,就可能会出现数据传输出错的情况.在数据传输的过程中低电平被干扰之后扰下就成了高电平,因此, 就需要校验和这一方法来识别出出错的数据.
        校验和,其实本质上也是一个字符串,体积比原始的数据更小,又是通过原始的数据生成的.
如果接收方收到的原始数据相同,得到的校验和就一定相同,;同理,校验和相同,原始数据大概率相同 (理论上会存在不同的情况, 实际的概率非常低,可以忽略不计)

        如何基于校验和来完成数据校验呢
1、发送方,把要发送的数据整理好(称为 data1),通过一定的算法,计算出校验和 checksum1;

2、发送方把data1和checksun1一同发送出去;

3、接收方收到数据,收到的数据称为 data2(数据可能和 data1 就不一样了),收到数据 checksum1;

4、接收方再根据 data2 重新计算校验和 (按照相同的算法),得到 checksum2
5、对比 checksum1 和 checksum2 是否相同.如果不同,则认为 data2 和 data1 一定不相同
如果 checksum1 和 checksum2 相同,则认为 data1 和 data2 大概率是相同的(理论上存在不同的可能性,概率比较低,工程上忽略不计)

        关于校验和的计算方法:

        计算校验和,有很多种算法,
1、此处 UDP 中使用的是 CRC 算法(循环冗余算法)
        把当前要计算校验和的数据,每个字节,都进行累加,把结果保存到这 两个字节的变量中,累加过程中如果溢出,也没关系;如果中间某个数据,出现传输错误,第二次计算的校验和就会和第一次不同
        CRC 这个算法其实不是特别的靠谱,导致两个不同的数据,得到相同的 crc 校验和的概率比较大(前一个字节恰好少1,后一一个字节恰好多1.)

2、md5/sha1 算法 (就只介绍 md5)
        这里有一系列的公式,来完成 md5 的计算,(咱们不需要考虑公式是啥样的,是一个
数学问题),但是咱们需要知道 md5 的特点:

        1.定长,无论你原始数据多长,计算得到的 md5,都是固定长度->校验和本身就不应该很长,要不然不方便网络传输
        2.分散,给定两个原始数据,哪怕绝大部分内容都一样,只要其中一个字节不同,得到的 md5 值都会差异很大(md5 也非常适合作为 hash 算法)
        3.不可逆。给定一个原始数据, 计算 md5,非常容易。但是给定 一个md5,还原出原始数据, 计算量非常庞入,以至于超出了现有计算机的算力极限,理论上是不可行的.

2.1.4 关于udp的特点分析

        通过之前所写的基于udp实现的通信代码来分析相关的特点:

1、无连接.UDP 协议本身不会存储对端的信息,要在发送数据的时候,显式指定要传输给谁

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

2、不可靠,代码中体现不出来

3、面向数据报

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

4、全双工 通过一个 socket,既可以 send, 又可以 receive

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

 2.1.5 基于UDP的应用层协议

NFS:网络文件系统

TFTP:简单文件传输协议

DHCP:动态主机配置协议

BOOTP:启动协议(用于无盘设备启动)

DNS:域名解析协议

2.2 TCP协议

        TCP协议最大的特点就是可靠性传输;

2.2.1 TCP报文格式

        TCP报文格式如下图所示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        首先:数据报 = 首部(报头 header) + 载荷 

四位首部长度:

        tcp报头长度是不固定的,报头最短,是20字节(没有选项);报头最长是60字节(一般来说选项最长的是40字节),4bit=>(0,0XF)此处的单位是4字节

保留(6位):

        UDP 有个问题,udp报文长度 64kb是固定的;所谓的保留位, 就是当前现在不用,但是先占个位置,后面如果有需要,再使用.(留下了扩展的余地~~)

16位检验和:

        和 udp 一样的校验和一样;

2.2.2 关于可靠传输

        可靠传输,是 TCP 最最核心的特性 (初心),并不是说,发送方把数据能够 100% 的传输给接收方,而是退而求其次:
1、发送方发出去数据之后,能够知道接收方是否收到数据.
2、一旦发现对方没收到,就可以通过一系列的手段来"补救.

        下面是一些确保信息可靠传输的补救手段:

1、确认应答
        发送方,把数据发给接收方之后,接收方收到数据就会给发送方返回一个应答报文(acknowledge, ack).发送方如果收到这个应答报文了,就知道自己的数据是否发送成功了;

        但是每天请求能及时的收到正确的应答这个情况太理想了,实际上网络传输数据可能会出现(后发先至--->一个数据包在进行传输的过程中走的路径可能是非常复杂的.即不同的数据包,可能走不同的路线.)这样的情况‘;

        TCP在此处要完成两个工作:
        1、确保应答报文和发出去的数据, 能对上号,不要出现歧义
        2、确保在出现后发先至的现象时,能够让应用程序这边仍然按照正确的顺序来理解数据

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        所谓的序号就是一个整数.大小关系,就描述了数据的先后顺序,准确的说,序号不是按照"一条两条"方式来进行编号的,而是按照字节来编号的,因为tcp是面向字节流的;

        对于序列号并不是我们自己设定的,序列号的情况如下图所示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        通过特殊的 ack 数据包,里面携带的"确认序号"告诉发送方,哪些数据已经被确认收到了
此时发送方,就心中有数了,就知道了自己刚发的数据是到了还是没到.=>TCP 的初心,是为了实现可靠传输 =>达成可靠传输的最核心的机制, 就是确认应答

        q1:如何区分一个数据包是普通的数据,还是 ack 应答数据呢?

        【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        q2:为啥确认序号是现在这样的规则?即用收到的最后一个字节的序号+1来表示呢
        主要是为了关联后面的知识->滑动窗口,

2、超时重传

        确认应答,描述的是一个比较理想的情况。但是如果网络传输过程中,出现丢包,则发送方,势必就无法收到 ACK 了,所以使用超时重传机制,针对确认应答,进行补充.

        为什么会丢包?
        把网络想象成公路,即错综复杂的公路网,在公路上就会有很多的收费站。平时车流量很通畅,但是当节假日的时候,收费站这里经常会堵车好几个小时;
        在网络中,“收费站"可以理解成是一些路由器/交换机,如果数据包太多了,就会在这些路由器/交换机上出现"堵车",但是路由器针对“堵车”的处理,不会把这些积压堵塞的数据包都保存好,而是会把其中的大部分数据包直接给丟弃掉.此时这个数据包就在网络上消失了,

        真实的网络环境,是错综复杂的,我们不会知道哪个节点上会出现上述"堵车"情况,也不知道啥时候会出现丢包, 丟包是非常随机的事件.这个事情出现概率的大小,取决于网络基础设施施,同时也取决于网络环境.

        综上所述,丢包是一个"随机”的事件,因此在上述 tcp 传输过程中,丢包就存在两种情况.

情况一:传输的数据丢了

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

情况二:返回的 ack 丢了

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        对于发送方的来说,无法区分这两种情况.无论出现上述哪种情况,发送方都会进行"重新传输”第一次是丢了,重传一下很大概率就能传过去;重传就是一个很好的丢包下的补救措施了

        q3:发送方,何时进行重传?

        引入等待时间,发送方发出去数据之后, 会等待一段时间, 如果这个时间之内, ack 来了,此时就自然视为数据到达;如果达到这个时间之后,数据还没到,就会出发重传机制

        q4:关于等待时间

        1、初始的等待时间,是可配置的.不同的系统上都不一定一样,也可以通过修改一些内核参数来引起这里的时间变化.
        2、等待的时间,也会动态变化.每多经历一次超时,等待时间都全变长(变长,隐含的含义,就是对能够正确传输数据这件事,前面按照丢包概率 10% 计算,每次重传一次都会让传输成功的概率大幅度增加.)

        eg:A->B发了一条数据,
        第一次,A 等待 ACK 的时间,假设是 50ms,此时如果达到 50ms, 还没有 ack,A 就重传;
当 A 重传的数据,还是没有收到 ack,第二次等待的时间就会比第一次更长,拉长也不是无限拉长,重传若干此时,时间拉长到一定程度,认为数据再怎么重传也没用了, 就放弃 tcp 连接(准确的说是会触发 tcp 的重置连接操作)

        q5:关于接受端收到两条一样的数据的bug处理

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        其实 TCP 已经非常贴心的帮我们把这个问题解决了;TCP 会有一个"接收缓冲区",就是一个内存空间,会保存当前已经收到的数据,以及数据的序号;
        接收方如果发现,当前发送方发来的数据,是已经在接收缓冲区中存在的 (收到过的重复
数据了),接收方就会直接把这个后来的数据给丢弃掉,确保应用程序进行 read 的时候,
读到的是只有一条数据,

        所谓的接受缓冲区,不仅仅是能进行去重,还能进行重新排序,确保发送的顺序,和应用程序读取的顺序是一致的;

3、连接管理
        即建立连接 + 断开连接

        建立连接:

        握手,只是为了唤起对方的注意,tcp 这里的握手,也是类似给对方传输一个简短的,没有业务数据的数据包,并通过这个数据包,来唤起对方的注意,从而触发后续的操作.

        TCP 的三次握手.TCP 在建立连接的过程中,需要通信双方一共"打三次招呼”才能够完成连接建立的,简单分析图如下所示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        A 想和 B 建立连接,A 就会主动发起握手操作;实际开发中,主动发起的一
方, 就是所谓的"客户端,被动接受的一方,就是"服务器”(同步报文段,就也是一个特殊的 TCP 数据包,没有载荷的 (不携带业务数据的))

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        q6:三次握手是要解决什么问题?通过四次握手,是否可行?通过两次握手,是否可行呢?

        可以, 但是没必要.两个数据合并成一个数据效率更高.

        q7:三次握手核心作用:

1、确认当前网络是否是畅通的,

2、要让发送方和接收方都能确认自己的发送能力和接收能力均正常

3、让通信双方,在握于过程中,针对一些重要的参数进行协商

        握手这里要协商的信息,其实是有好几个的,至少大家要知道,tcp 通信过程中的序号从几开始,就是双方协商出来的(一般不是从1 开始的),每次连接建立的时候,都会协商出一个比较大的,和上次不太一样的值.

        这种设定方式,是避免“前朝的剑,斩本朝的官"----->

        有的时候,网络如果不太好,客户端和服务器之间可能会连接断开, 再重新建立连接;重连的时候, 就可能在新的连接好了之后,旧连接的数据姗姗来迟,这种迟到的数据,应该要丢弃掉的! 不应该让这个之前的的数据影响到本次的业务逻辑~
        如何区分数据是否是来自于上个朝代?就可以通过上述序号的设定规则来实现->如果发现收到的数据序号和当前正常数据的序号差异非常大就可以判定为是上个连接的数据就可以直接丢弃了;

断开连接,四次挥手:

        建立连接,一般都是客户端主动发起;断开连接,客户端和服务器都可以主动发起

        四次挥手的简单分析如下所示:

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        q8:和 三次握手 不同,此处的四次挥手,能否把中间的两次交互合二为一?不一定!!

        不能合并的原因是因为ACK 和 第二个 FIN 的触发时机是不同的.ACK 是内核响应的.B 收到 FIN,就会立即返回 ACK;第二个 FIN 是应用程序的代码触发.B 这边调用了 close 方法才会触发 FIN ->

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        从服务器收到 FIN(同时返回 ACK),再到执行到 close发起 FIN,这中间要经历多少时间,经历多少代码,是不确定的!!FIN 就会在 socket 对象 cose 的时候, 被发起.可能是手动调用 close 方法也可能是进程结束.故此综上所述:

       象前面的三次握手, ACK 和 第二个 syn 都是内核触发的.因为是同一个时机,可以合并;但是这里的四次挥手, ACK 是内核触发的,第二个 FIN 是应用程序执行 close 触发的,二者的的触发时机不相同,所以不能合并.

        是否意味着,如果我这边代码 close 没写/没执行到,是不是第二个 FIN 就一直发不出去??(有可能的),并非所有的连接都是好聚好散;但是,TCP 中还有一个机制->延时应答,(后面再说),能够拖延 ACK 的回应时间一旦 ACK 滞后了,就有机会和下一个 FIN 合并在一起了

        【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

        q8:TIME_WAIT 状态主要存在的意义?

        如果最后一个 ACK 丢了,站在 B 的角度,B 就会触发超时重传重新把刚才的 FIN 给传一遍,如果刚才 A 没有 TIME WAIT 状态, 就意味着 A 这个时候就已经真的释放连接了,此时重传的 FIN 也就没人能处理, 没人能返回 ACK 了.B 永远也收不到 ACK 了

        A这边使用 TIME_WAIT 状态进行等待,等待的这个时间,就是为了处理后续 B 重传的 FIN此时有重传的 FIN 来了, 就可以继续返回 ACK 了.B 这边的重传 FIN 才有意义.

        q9:TIME WAIT 等待多久呢?

【Java EE初阶十六】网络原理(一),JAVA EE 初阶,网络

ps:本篇的内容就到这里了,如果大家感兴趣的话就请一键三连哦!!!

       

        文章来源地址https://www.toymoban.com/news/detail-828025.html

到了这里,关于【Java EE初阶十六】网络原理(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java EE 初阶】文件操作

    目录 1.什么是文件? 1.在cmd中查看指定目录的树形结构语法 2.文件路径 从当前目录开始找到目标程序(一个点) 返回到上一级目录,再找目标程序(两个点) 2.Java中文件操作 1.File概述 1.属性 2. 构造方法 3.常用方法  代码展示: 4.常用方法2 3. 文件内容的读写---数据流 1.I

    2024年02月06日
    浏览(43)
  • 【Java EE初阶六】多线程案例(单例模式)

            单例模式是一种设计模式,设计模式是我们必须要掌握的一个技能;         设计模式是软性的规定,且框架是硬性的规定,这些都是技术大佬已经设计好的;         一般来说设计模式有很多种,且不同的语言会有不同的设计模式,(同时 设计模式也可

    2024年02月03日
    浏览(42)
  • 【Java EE 初阶】TCP协议的安全效率机制

    目录 1.应用层协议 2.传输层协议 3.UDP协议格式 4.TCP协议格式 5.TCP的安全效率机制 1.确认应答机制 2.超时重传机制 但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了; 3.连接管理机制 ​编辑 面试题:会不会有可能变成三次挥手? 面试题:第二个FIN丢包了如何处理?

    2024年02月09日
    浏览(45)
  • 【Java EE初阶三 】线程的状态与安全(下)

             线程安全 : 某个代码,不管它是单个线程执行,还是多个线程执行,都不会产生bug,这个情况就成为“线程安全”。          线程不安全 : 某个代码,它单个线程执行,不会产生bug,但是多个线程执行,就会产生bug,这个情况就成为 “线程不安全”,或者

    2024年02月03日
    浏览(45)
  • 【Java EE初阶八】多线程案例(计时器模型)

            计时器类似闹钟,有定时的功能,其主要是到时间就会执行某一操作,即可以指定时间,去执行某一逻辑(某一代码)。         在java标准库中,提供了Timer类,Timer类的核心方法是schedule( 里面包含两个参数,一个是要执行的任务代码,一个是设置多久之后

    2024年01月21日
    浏览(46)
  • 【Java EE初阶二十二】https的简单理解

             当前网络上,主要都是 HTTPS 了,很少能见到 HTTP.实际上 HTTPS 也是基于 HTTP.只不过 HTTPS 在 HTTP 的基础之上, 引入了\\\"加密\\\"机制;引入 HTTPS 防止你的数据被黑客篡改 ;         HTTPS 就是一个重要的保护措施.之所以能够安全, 最关键的在于\\\"加密”;         明文:

    2024年02月22日
    浏览(53)
  • 【Java EE初阶二十一】http的简单理解(二)

            Referer 描述了当前页面是从哪个页面跳转来的,如果是直接在地址栏输入 url(或者点击收藏夹中的按钮) 都是没有 Referer。如下图所示:         HTTP 最大的问题在于\\\"明文传输”,明文传输就容易被第三方获取并篡改.         HTTPS 针对 HTTP 数据进行了加密 (h

    2024年02月22日
    浏览(39)
  • JVM工作原理与实战(十六):运行时数据区-Java虚拟机栈

    JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、运行时数据区 二、Java虚拟机栈 1.栈帧的组成 2.局部变量表 3.操作数栈 4.帧数据 总结 JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具

    2024年01月20日
    浏览(42)
  • 【Java EE】文件操作

    目录 1.认识文件 2.树型结构组织和目录 3.文件路径(Path) 4.其他知识 5.Java中操作文件 5.1File概述 5.1.1属性 5.1.2构造方法 5.1.3方法 5.2代码示例 1.认识文件 我们先来认识狭义的文件(file)。针对1硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存一个整

    2024年04月22日
    浏览(54)
  • JAVA EE 第一周

    计算机Z20-第1周作业        总分:100分              1 . 单选题 简单 6分 下列选项中,哪些属于网站建设常用技术( )。 A.HTML B.JavaScript C.CSS D.以上都是 2 . 单选题 简单 6分 下列选项中,哪个不是静态网页的文件扩展名( )。 A.xml B.jsp C.htm D.shtml 3 . 单选题 简单 6分

    2024年02月06日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包