终于懂了TCP协议为什么是可靠的,计算机基础(六)之运输层

大家好,我是后来,我会分享我在学习和工作中遇到的点滴,希望有机会我的某篇文章能够对你有所帮助,所有的文章都会在公众号首发,欢迎大家关注我的公众号" 后来X大数据 ",感谢你的支持与认可。

不知不觉我的计算机网络专栏已经写了5篇了,今天是第6篇,到运输层了。其中第4篇警察叔叔顺着网线是怎么找到你的?计算机网络(四)之网络层未完待续阅读量最高。
在这里插入图片描述
通过学习计算机网络,开始逐渐理解了两台主机之间是如何进行通信的,但是还有一个问题困扰着我,我们为啥非要下载一个微信才能一起聊天,难道不能你用微信,我用QQ么,也就是微信上发的消息为啥不会出现在QQ上呢?

带着这个疑问我们来看今天的内容。来划重点了:

  1. 通信实质上是进程之间的通信
  2. 端口和套接字的意义
  3. 用户数据报协议UDP
  4. 传输控制协议TCP
  5. 三次握手
  6. 四次挥手
  7. 可靠传输是如何实现的?

还是老样子,这张图再来看一遍,现在应该记住了吧,毕竟在我的文章里已经出现了5次了。
在这里插入图片描述

1、运输层是干啥的?

从上图能看到,运输层是向它上面的应用层提供通信服务的。

抛开这些复杂的逻辑,我们回到我写文章最开始的问题:我发的文章怎么到你手机上了?
为了简单讨论原理,我们把问题同理为:我给你发的微信消息为什么只会出现在你的微信上?而不是QQ上

我们之前通过网络层的IP地址与MAC地址,已经把消息发送到了主机里,那么大家知道我们的电脑同时执行着多个进程,比如在座的各位,平时是不是一边聊微信,一边看浏览器。
在这里插入图片描述
重点:通信的真正的端点不是主机,而是主机中的进程
所以,消息到了网络层,再发到那个进程的这件事已经不归网络层管了,而是归运输层管

1.1 那么运输层咋管呢?——端口号

那么消息已经到了主机的网络层,

  1. 运输层首先得分清楚哪条消息是发给哪个进程的吧?
    这个时候就需要一个标识符来进程区分,而且这个标识符必须是全世界统一,不然每个电脑厂家都有自己的一套,那对于用户来说,就太不方便了,所以就在运输层使用协议端口号,简称为端口(port),为端口(port),也就是说,虽然通信的终点是应用进程,但只要把所传送的报文交到目的主机的某个合适的目的端口,剩下的工作(即最后交付目的进程)就由TCP或UDP来完成。
    在这里插入图片描述
    注意,这个端口是一个虚拟的端口号,0-65534,而不是指的电脑插网线的那个真实存在的端口。
    重点:通信的真正的端点不是主机,而是主机中的进程,使用端口号来标识进程

  2. 其次,运输层还要对收到的报文进程差错检测
    也就是看又没有异常,我们之前提到网络层是不可靠的,那么下面这几层都不咋负责,运输层得担起责任啊,所以运输层根据应用程序的不同需求,有两种不同的运输协议,那就是今天的重点:面向连接的TCP协议和无连接的UDP协议。
    这个协议有啥好处,它让你觉得,你在使用微信聊天时,感受是:你的微信在和对方的微信聊天,直接屏蔽了底层的细节,好像是两个运输层直接通信一样。

综上所述:

  1. IP协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付主机中的应用进程。
  2. 从运输层的角度看,真正进行通信的实体是在主机中的进程,是这台主机中的一个进程和另一台主机中的一个进程在交换数据(即通信)。 在一台主机中经常有多个应用进程同时分别和另一台主机中的多个应用进程通信。

看到这里,大家发现,运输层会对收到的消息进程分端口交付,这叫分用;对需要发送出去的消息会打包在一起发给网络层,这叫复用;这个过程像什么?像不像一个快递网点?所以运输层的特点也总结出来了:分用与复用

1.2 端口的再了解

其实关于端口,对程序员来说,再熟悉不过了。TCP/IP体系协议的运输层用16位的端口号来标志一个端口,也就是说只有65535个端口,这对于一个计算机来说是足够使用的。同时,这个端口只具有本地意义;在不同的计算机中,相同的端口号是没有关联的。

所以说,在互联网里进行通信,要知道对方的IP地址,MAC地址,还有端口号,才行,这可以称为是通信3剑客
端口号分为2大类:

  1. 服务器端使用的端口号
    1 熟知端口号 :0~1023
    在这里插入图片描述
    2 登记端口号:1024~49151
  2. 客户端使用的端口号:49152~65535

那么怎么表示一个TCP连接呢?
每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。 即:
套接字 socket = {IP地址 : 端口号}
TCP 连接 :: =(socket1_1, socket2_2)=((IP1_1: port1_1),(IP22_2: port2_2)
套接字是抽象的,只是为了表示TCP连接而存在。

在讲下面的协议前,大家一定要知道,TCP是全双工的通信,就是说A可以给B发消息,B同时也可以给A发消息。我们在下面的举例中,为了简便只考虑时单向。

先把题目中的问题解答一下:微信和QQ属于2个不同的进程,所以在一台主机中进程之间的端口号不一样,所以当微信发送的消息通过网络层到达目的主机后,通过运输层对端口的判断,会把对应的消息会交付给目的主机中负责微信的进程。而不会选择QQ,所以这个问题的关键还是端口。

但是只知道个端口并不能说你了解运输层,因为TCP协议才是运输层的核心。来跟着我的思路一起了解一下运输层吧。

2、用户数据报协议UDP

这么说吧,UDP协议大概意思是,我给你传数据,等于我去你家串门,我不需要知道你方便不方便以及在不在家,我直接去了,去了之后能进去就进去,进不去就算了。所以UDP是不可靠传输

那么TCP协议就不一样了,我给你传数据,必须要确保你能接收,也就是要通过试探的问一下,你在不在,通过后面讲的3次握手方式,先建立连接,然后才正儿八经的发数据。最后走的时候,还要通过4次挥手的方式离场。所以TCP是可靠传输。

我们在这里有个大概印象后再来看UDP协议的特点。着重说一下第3点和第4点

  1. UDP是无连接的
  2. UDP不保证可靠交付
  3. UDP面向报文
    发送方: UDP对应用层交下来的报文,在添加首部后就向下交付IP层。既不合并,也不拆分
    接收方: UDP对IP层交上来的UDP用户数据报,在去除首部后就原封不动的交付给应用层。
    在这里插入图片描述
  4. UDP没有拥塞控制:发送方的UDP只管发,至于接收方能不能收到以及收到处理的速度怎么样,发送方不关心。其实微信视频电话就是这种模式,所以在网络不好的时候可能会断断续续的,但是也不会把数据重新发一遍。
  5. UDP支持一对一、一对多、多对一、多对多的交互通信
  6. UDP的首部开销小,只有8字节,而TCP有20字节。

2.1 UDP的首部格式

初学者只需要知道:UDP首部中包含了

  1. 源端口
  2. 目的端口
  3. 长度
  4. 检验和
    在这里插入图片描述
    也就是把自己的端口和目的端口放进去,给了网络层,网络层再包上IP地址以及目标MAC地址,就把数据发出去了。那么接收方收到后,网络层再通过UDP首部知道是从哪儿发来的,以及要发给哪个端口。

同时UDP协议还要做差错检验,如果目的端口号不正确(不存在对于端口的进程),就丢弃该报文,并让网络层ICMP协议发回去”端口不可达“。这个时候,其实通信已经完成了。
还有检验和的这个方法就不说了,反正也不是很简单,说一遍也不是很懂,有兴趣深入了解的可以去查资料啦。

3、面向连接的TCP协议(重头戏)

这才是今天的重头戏,也比较复杂,个人水平有限,我就把一些比较重要的拿出来说。

我们在前面也粗略的说了TCP协议是可靠传输,那么TCP协议是怎么实现可靠传输的?

千万别以为只是因为TCP协议是面向连接这么简单,比如:我已经确认你在了,但是我发消息的速率是不是太快,没收到你的确认收到的消息,我是不是应该重发?这中间怎么提高效率才达到提到信道利用率的目的?

那么我们先从建立连接开始说起:

3.1 3次握手

之前有漫画画过这个原理,比较形象,我们为了说明问题,只考虑单向发送消息, 假设A是客户端,是要发消息,B是服务器,是收消息的。
那么连接图如下:
在这里插入图片描述
第一眼看不懂再看下一张图,我画的还行吧
在这里插入图片描述
看完基本能明白3次握手,那再返回来看第一张图,我们来从原理层面理解一下TCP协议:

  1. 最初的两端TCP都是处于关闭状态,A客户端主动打开,B服务端被动打开后就处于收听状态,准备做出响应
  2. A向B发送连接请求报文段,首部的同步位SYN=1,同时初始序号seq = x(这里的首部的字段我下面会解释),其实这个时候,并不携带数据,也就是只试探性的请求一下。
  3. B收到连接请求报文段后,如果同意建立连接,会向A发送确认。确认的时候SYN=1,ACK=1,确认号ack=x+1,同时也选择一个初始序列号seq=y。这个时候的B就处于SYN-RCVD(同步收到)状态
  4. A收到B的确认信息后,还要向B给出确认,确认报文段的ACK=1,确认号ack=y+1,而序列号seq=x+1。这个时候A处于ESTABLISHED(已建立连接)状态。
  5. B收到A的确认后,也进入ESTABLISHED(已建立连接)状态。

但其实:
B发给A的报文段,其实是2个报文段的合并, 先确认报文段(ACK=1,ack=x+1),然后再发送一个同步报文段(SYN=1,seq=y)。所以这样的话就是4次握手,但效果却是一样的。所以我们目前都说是3次握手。

问题:为社么A最后还要发送一次确认呢?
答:为了防止已失效的连接请求报文段突然又传送到了B,因为产生错误
听不太懂?我来举个例子:
假如现在是2次握手,那么A发出请求后,迟迟没有收到B的确认,于是A就重传请求。然后很快这次就建立了连接。到目前为止还没有问题,但是:
第一次发出去的请求并没有丢失,而是在某个网络节点滞留了,所以延迟了一会儿到达了B,这个时候B以为是A发出的新请求,又同意了。但是这个时候A早就忘了还有这个请求了,所以也不会理睬B的确认,也不会向B发送数据,所以这个给连接的资源就被浪费了。

3.2 4次挥手

刚刚说的是建立连接,那么等到数据发送完了,双方都可以释放连接,那怎么断开连接呢?我们为了简单说明原理,还是假设A先断开连接
在这里插入图片描述
老样子,看不懂就看我画的图:
在这里插入图片描述
大概理解了我们来看看原理:

  1. 现在A和B都处于 ESTABLISHED状态,A先向自身的TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接。A把连接释放报文段首部的终止控制位FN置1,其序号seq=u,这时A进入 FIN-WAIT-1(终止等待1)状态,等待B的确认。
  2. B收到连接释放报文段后即发出确认,确认号是ack=u+1,而这个报文段自己的序号是v,等于B前面已传送过的数据的最后一个字节的序号加1。然后B就进入 CLOSEWAT(关闭等待)状态。【TCP服务器进程这时应通知高层应用进程,所以从A到B这个方向的连接就释放了,这时的TCP连接处于半关闭( half-close)状态,即A已经没有数据要发送了,但B若发送数据,A仍要接收。也就是说,从B到A这个方向的连接并未关闭,这个状态可能会持续一段时间。】
  3. A收到来自B的确认后,就进入 FIN-WA2(终止等待2)状态,等待B发出的连接释放报文段。若B已经没有要向A发送的数据,其应用进程就通知TCP释放连接。这时B发出的连接释放报文段必须使FN=1。
  4. 现假定B的序号为w(在半关闭状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认号ack=u+1。这时B就进入LAST-ACK(最后确认)状态,等待A的确认。
  5. A在收到B的连接释放报文段后,必须对此发出确认。在确认报文段中把ACK置1,确认号ack=w+1,而自己的序号是seq=u+1。然后进入到 TIME-WAIT(时间等待)状态。【请注意,现在TCP连接还没有释放掉。必须经过时间等待计时器( TIME- WAIT timer)设置的时间2MSL后,A才进入到 CLOSED状态。时间MSL叫做最长报文段寿命 Maximum Segment Lifetime),RFC793建议设为2分钟,但实际中允许不同的实现允许比较小的MSL值。】

好了,关于TCP连接的建立与释放就到这里了。到这里,我已经花了3个多小时了,可是还有一部分还没写完。

3.3 可靠传输的工作原理

我们上面只是建立了连接,要想做到可靠传输,还得在传输的时候信道不产生差错,以及不管发送方发的多快,接收方总能处理完。
但现实终究是很残酷的,所以我们需要使用可靠传输协议

3.3.1 停止等待协议

这个协议是比较简单的。简单说就是:
发一条消息,收到对方确认再发下一条。
如果没收到确认,就认为是出错了,超时重传。
在这里插入图片描述
但是如果B确认的消息丢失了,导致A又重新发了一遍,B应该丢弃重复数据再向A发确认收到。
如果B确认的消息迟到了,B就会收到2次数据,那么B应该丢弃重复数据再向A发确认收到,同时A会收到2次确认,但收到第二次确认就什么也不做。
在这里插入图片描述
这里面注意的是超时时间不是固定的,具体怎么取值后面3.5再讲。

我们发现这种协议虽然能实现可靠传输,但是信道利用率太低了。
在这里插入图片描述
假定A发送分组需要的时间是TD,B发送确认分组需要时间TA。消息往返时间RTT,因此信道的利用率U=TD/(TD+RTT+TA)

3.3.2 连续ARQ协议

所以为了提高传输效率,发送方可以使用流水线传输
在这里插入图片描述
其实看到这里的时候,我感觉有点像大数据处理中Spark与Flink的窗口函数的原理。
这个ARQ是TCP协议的精髓,所以大家还是大概理解一下:

就好比是A员工给B老板发一些带顺序编号的文件。
假设窗口是5,也就是说可以连续发5个文件不能等老板一个一个确认收到,但是假如发完这5个文件后,老板一个也没回复你,你就不能发第6个文件,我们把这个5称为窗口。
在这里插入图片描述
但是问题是:老板比较忙,所以只会回复当前收到最后一个文件的序号,对于中间的可能会丢失。但对于A来说,只要收到确认,那么就可以继续发送了,总之窗口不能超过5

这样的话有好有坏:
好处是:如果网好的话,A发的文件B都收到了,直接回复5,那么A就可以继续发5个了
坏处是:假如网不好,A发了5个文件,B却只回复2,这个时候,A就只能认为另外3个丢失了,再把后面的文件重新传一遍。

其实了解到这里,关于运输层的可靠传输已经有了基本的了解,如果你想再具体的知道ARQ协议是怎么优化的? 那么接着看下面的内容。

要想深入了解,还得返回来再看看TCP报文段的首部格式:

3.4 TCP报文段的首部格式

在这里插入图片描述
我们再上面这些众多的标签里面挑重点的说一下:

  1. 源端口和目的端口: 各占2个字节,目的从字面上也能看出来,体现了TCP的分用功能
  2. 序号: 占4个字节,所以范围就是【0,2的32次-1】= 4294967296 个序号。当序号到达最大以后,下一个序号就回到0。这里的序号就等于上面的ARQ协议中的文件编号,文件=字节。是怎么实现的,就是这里一个个编好的。而且这么多序号大概可以为4GB的数据编号,所以在一般情况下,当序号重复使用时,旧序号的数据早已经通过网络到达终点了。
  3. 确认号,占4个字节。虽然是确认呢,但它发的是期望收到对方下一个报文段的第一个数据字节的序号。比如上面例子中的老板回复3意味着,它希望下次从3开始发,1和2他已经收到了。
  4. 数据偏移
  5. 保留
  6. 紧急URG(URGent) 当URG=1时,表明此报文字段有紧急数据,应尽快传送,优先级高于普通数据,也就不会按照之前的排队顺序来传送
  7. 确认ACK ACK=1才表示确认号有效,所以在建立连接后所有的报文段的ACK都等于1
  8. 推送PSH(push)很少使用
  9. 复位RST(reset)当RST=1表示TCP连接中出现问题,需要释放连接重新建立连接
  10. 同步SYN(synchronization)在建立连接时来同步序号
  11. 终止FIN(finis)当FIN=1,表示此报文段的数据发完了,要释放连接
  12. 窗口 占2字节,窗口指的是,接收方的接收窗口,因为接收方的数据缓存空间是有限的。窗口字段动态变化
  13. 检验和:2字节
  14. 紧急指针:2字节。它只在URG=1的时候才有意义。
  15. 选项:长度可变,最大40字节。

终于把这些字段大概解释完了,应该对之前3次握手和4次挥手中的一次名词眼熟了吧。

知道这个首部格式后,就为后面的理解奠定了基础。我们再来返回来看之前的滑动窗口的实现:下面就是给举例子啦,认证看都能看懂!!!
在这里插入图片描述
现在假定A发送了序号为31~41的数据。这时,发送窗口位置并未改变

但发送窗口内靠前面有11个字节(黑色小方框表示)表示已发送但未收到确认。而发送窗口内靠后面的9个字节(42~50)是允许发送但尚未发送的。

但现在A是发出去了,那么B收到的情况怎么样呢?
B的接受也是20,目前30号之前的是确认过的,这部分数据已经交付了,B的缓存就可以不保存。目前B收到了序号32和33,但是乱序的,而31也不知道去哪鬼混了,可能是丢失了。那么B该怎么发送确认消息呢?
B只能对按序收到的数据中的最高序号给出确认, 也就是确认号依然为31,也就是期望收到的下一个序号仍然是31。
在这里插入图片描述
假设现在B收到了31-33并且确认号回复了34,那么A的窗口会向前滑动,保持20大小。
在这里插入图片描述
同时B的窗口也会向前滑动
在这里插入图片描述
但时能发现其实序号37,38和40,B也收到了,只是没有按序到达,那么就先暂时存在B的接收窗口中,等到其他数据也到了再回复确认。
但是此时A已经把它窗口中的序号都发送完了,但B还没有新的确认回复,那么此时的A就不能继续发消息了,只能等待B的确认回复
在这里插入图片描述
所以通过上面的这段举例,我们发现发送方,把字节流写入TCP的发送缓存,接收方呢从TCP的接受缓存读取字节流。 大概就是下面这个样子。
在这里插入图片描述

3.5 超时重传时间的选择

我们在上面讨论的是正常网络情况下,B都收到了A的消息,但是假如网络状态不好,A发的消息B迟迟没有回复,A就会触发超时重传,但是这个超时的时间到底是多少合适呢? 这个时间固定了肯定是不好,因为网络的状态是不确定的,所以TCP采用了一种自适应算法

我把公式贴一下,看不懂的略过
RTO=RTTs + 4 X RTTd
好了,问题来了。RTTs是什么?RTTd又是什么?

首先大家应该还记得这张图吧:
在这里插入图片描述
我们把报文的往返时间记为RTT,那么还记的在TCP连接时,就第一次测出来了RTT值,那个就是RTT样本值。

所以规定:当第一次获取RTTs的值时,就RTTs = RTT样本值
但以后每测量到一个新的RTT样本,就按照下面这个公司再算一次:
新的RTTs=(1-a) X (旧的RTTs)+ a X (新的RTT样本)

好了,我们再来看RTTd是什么?
RTTd是RTT 的偏差的加权平均值,说到加权,就想一想初中二年纪的只是吧。
规定:
当第一次获取RTTd的值时,RTTd = RTT样本值/2
在以后的测量时:用下面的公式计算:
新的RTTd=(1-B) × (旧的RTTd) + B x |RTTs-新的RTT样本|
而这个B推荐值是0.25

好了,我知道这公式你也不会去看的,那么反正知道了超时重传时间不是固定的而是算出来的就行了。

那么再来思考一个问题:A现在发消息后超时重传了,相当于消息发了2次,但问题是原本的消息并没有丢失,而是网络延迟,现在A收到B的确认消息了,A怎么知道B是对第一次发送的消息进行确认还是对后来补发的消息进行确认?
在这里插入图片描述
为什么还要思考这个问题呢?因为如上图所述,这涉及到新的RTT样本值计算是以那次发送消息的时间为准。
如果是确认重传报文,被源主机当作是确认首次发送的消息,那就会RTT样本值增大,重传时间RTO偏大,这样的情况发送多次,就使得RTO越来越长
如果是确认首次发送的报文,但被源主机当作是确认重传报文,那就会使得RTT样本值偏小,重传时间RTO偏小,这样就会导致报文段过多的重传,使得RTO越来越短。

所以,最后大牛们讨论得到这样的算法:报文段每重传一次,新的重传时间为旧的重传时间的2倍。当不再发生报文段的重传时,才根据上面给出的公式计算超时重传时间。 实践证明,这种策略较为合理。

3.6 选择确认SACK

现在看似问题都基本得到了解决,但还有个小问题,就是当B收到的数据字节流的序号是断断续续的话,怎么办?
在这里插入图片描述
如果按照之前的约定,只返回按照顺序收到的最大的序号,那么就意味着这些断断续续的字节都得重新发送,其实有点浪费,那么能不能把这些缺失的序号告诉A,这样A就不用全部重新发送了,于是就在TCP首部的可选字段中,现在多出来了一个选择确认块。

但目前文档并没有说明A收到选择确认块后,该如何响应。所以导致其实目前大多数的实现还是重传所有未被确认的数据块。

长出一口气,写了7000多字了,还没结束,看到这里的你绝对是个狠人,虽然知道写这么长,看的人没几个,但学习嘛还是为了自己而学。

3.7 TCP的流量控制

我们在上面通过大段的篇幅已经实现了TCP 的可靠传输,但是没考虑A发消息的速度到底是多少合适? 太快吧B来不及处理,太慢吧又浪费信道资源。所以就有了流量控制这个学问:让发送方的发送速率不要太快,要让接受方来得及接收。

所以,大牛们研究出来了滑动窗口机制。这个大家在上面已经知道了,就是通过窗口大小来控制。

那么思考一个问题:目前A已经把窗口内的字节都发送完了,不能再发送了,除非等到B的确认号,这样A的窗口才能继续向后移动,但可恶的是B的确认信号却在半路上丢失了,那现在A在等B发确认,B以为A收到了,在等A发数据。形成了死锁
在这里插入图片描述
所以为了解决死锁问题,TCP为每一个连接都设有一个持续计时器,只要A第一次收到B的确认,就启动持续计时器。若持续计时器设置的时间到,就发送一个零窗口探测报文段〔仅携带1字节的数据),而对方就在确认这个探测报文段时,给出了现在的窗口值。如果窗口仍然是零,那么收到这个报文段的一方就重新设置持续计时器。如果窗口不是零,那么死锁的僵局就可以打破了

好了,死锁解决了,还有个效率问题,举个例子:
B的窗口值是400 ,现在A已经发完了该窗口内的400个字节,不能再发了,但是现在A收到了B确认号,但显示只能向后一个字节,那么问题来了,A只能发送一个字节,有没有必要专门发一次? 还是攒着等B确认到所有字节后A再继续发?

大牛们又通过考虑,规定:

可以让接收方等待一段时间,

  1. 使得接收缓存已有足够空间容纳一个最长的报文段
  2. 或者等到接收缓存已有一半空闲的空间

只要出现这两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。

此外发送方也不要发送太小的报文段,而是把数据积累成足够大的报文段,或达到接收方缓存的空间的一半大小。
上述两种方法可配合使用。

嗯,到目前为止,TCP还剩下一个拥塞控制没有说,这个主要讲的是:

对资源的需求 > 可用资源

这个时候就出现了网络拥塞,这个里面的算法已经超出我的理解范围了,所以我就跳过了。

但是本文到底为止讲述的关于运输层的内容还是不少的,最后一个问题也不会影响大家整体理解运输层。

4、本文收尾

OMG,这篇文章终于写完了,一共花费时间大概在8小时左右,而我第一次看这章只需要不到2小时。但我现在写完之后对运输层的理解肯定是比第一次看完要深。

本文内容是根据《计算机网络(第7版)谢希仁》写的,我也是看完后写的,所以文章的图还有部分内容都是直接引用的该书。

下次就把最后一层应用层写完。希望对大家能有所帮助。如果觉得写的还不错,就点赞收藏鼓励一下吧。

扫码关注公众号“后来X大数据”,回复【电子书】,领取超多本pdf 【java及大数据 电子书】

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章