摘要:收到了,發(fā)送,要求下一個(gè)是,不幸又丟了。在對(duì)于包的確認(rèn)中,會(huì)同時(shí)攜帶一個(gè)窗口大小的字段。前面的滑動(dòng)窗口是怕發(fā)送方把接收方緩存塞滿,而擁塞窗口,是怕把網(wǎng)絡(luò)塞滿。這里有一個(gè)公式可以看出,是擁塞窗口和滑動(dòng)窗口共同控制發(fā)送的速度。
網(wǎng)絡(luò)協(xié)議 1 - 概述
網(wǎng)絡(luò)協(xié)議 2 - IP 是怎么來(lái),又是怎么沒(méi)的?
網(wǎng)絡(luò)協(xié)議 3 - 從物理層到 MAC 層
網(wǎng)絡(luò)協(xié)議 4 - 交換機(jī)與 VLAN:辦公室太復(fù)雜,我要回學(xué)校
網(wǎng)絡(luò)協(xié)議 5 - ICMP 與 ping:投石問(wèn)路的偵察兵
網(wǎng)絡(luò)協(xié)議 6 - 路由協(xié)議:敢問(wèn)路在何方?
網(wǎng)絡(luò)協(xié)議 7 - UDP 協(xié)議:性善碰到城會(huì)玩
網(wǎng)絡(luò)協(xié)議 8 - TCP 協(xié)議(上):性惡就要套路深
????上次了解了 TCP 建立連接與斷開(kāi)連接的過(guò)程,我們發(fā)現(xiàn),TCP 會(huì)通過(guò)各種“套路”來(lái)保證傳輸數(shù)據(jù)的安全。除此之外,我們還大概了解了 TCP 包頭格式所對(duì)應(yīng)解決的五個(gè)問(wèn)題:順序問(wèn)題、丟包問(wèn)題、連接維護(hù)、流量控制、擁塞控制。今天,我們就來(lái)看下 TCP 又是用怎樣的套路去解決這五個(gè)問(wèn)題的。
????在解決問(wèn)題之前,咱們先來(lái)看看 TCP 是怎么成為一個(gè)“靠譜”的協(xié)議的。
“靠譜”協(xié)議 TCP????TCP 為了保證順序性,每個(gè)包都有一個(gè) ID。這建立連接的時(shí)候,會(huì)商定起始 ID 的值,然后按照 ID一個(gè)個(gè)發(fā)送。
????為了保證不丟包,對(duì)于發(fā)送的包都要進(jìn)行應(yīng)答。但是這個(gè)應(yīng)答不是一個(gè)一個(gè)來(lái)的,而是會(huì)應(yīng)答某個(gè)之前的 ID,表示都收到了,這種模式稱(chēng)為累計(jì)確認(rèn)和累計(jì)應(yīng)答。
為了記錄所有發(fā)送的包和接收的包,TCP 也需要發(fā)送端和接收端分別用緩存來(lái)保存這些記錄。發(fā)送端的緩存里是按照包的 ID 一個(gè)個(gè)排列,根據(jù)處理的情況分成四個(gè)部分:
第一部分:發(fā)送且已經(jīng)確認(rèn)的;
第二部分:發(fā)送尚未確認(rèn)的;
第三部分:沒(méi)有發(fā)送,但是已經(jīng)等待發(fā)送的;
第四部分:沒(méi)有發(fā)送,并且暫時(shí)還不會(huì)發(fā)送的。
????于是,發(fā)送端需要保持這樣的數(shù)據(jù)結(jié)構(gòu):
LastByteAcked:第一部分和第二部分的分界線
LastByteSent:第二部分和第三部分的分界線
LastByteAcked:第三部分和第四部分的分界線
對(duì)于接收端來(lái)講,它緩存記錄的內(nèi)容要簡(jiǎn)單一些,分為以下三個(gè)部分:
第一部分:接收且確認(rèn)過(guò)的;
第二部分:還沒(méi)接收,但是馬上就能接收的;
第三部分:還沒(méi)接收,也沒(méi)空間接收的。
????對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)就像這樣:
MaxRcvBuffer:最大緩存量;
LastByteRead:這個(gè)值之后是已經(jīng)接收,但是還沒(méi)被應(yīng)用層讀取的;
NextByteExpected:第一部分和第二部分的分界線,下一個(gè)期待的包 ID。
????第二部分的窗口有多大呢?
????NextByteExpected 和 LastByteRead 的差起始是還沒(méi)被應(yīng)用層讀取的部分占用掉的 MaxRcvBuffer 的量,我們定義為 A,即:A = NextByteExpected - LastByteRead - 1。
????那么,窗口大小,AdvertisedWindow = MaxRcvBuffer - A。
????也就是:AdvertisedWindow = MaxRcvBuffer - (NextByteExpected - LastByteRead - 1)
????而第二部分和三部分的分界線 = NextByteExpected + AdvertisedWindow - 1 = MaxRcvBuffer + LastByteRead。
順序與丟包問(wèn)題????接下來(lái),我們結(jié)合上述圖例,用一個(gè)例子來(lái)看下 TCP 如何處理順序與丟包問(wèn)題的。
還是剛才的圖,在發(fā)送端看來(lái):
1、2、3 是已經(jīng)發(fā)送并確認(rèn)的;
4、5、6、7、8、9 都是發(fā)送未確認(rèn)的;
10、11、12 是還沒(méi)發(fā)出的;
13、14、15 是接收方?jīng)]有空間,不準(zhǔn)備發(fā)送的。
而在接收端看來(lái):
1、2、3、4、5 是已經(jīng)完成 ACK,但還沒(méi)讀取的;
6、7 是等待接收的;
8、9 是已經(jīng)接收,但是沒(méi)有 ACK 的。
發(fā)送端和接收端當(dāng)前的狀態(tài)如下:
1、2、3 沒(méi)有問(wèn)題,雙方達(dá)成了一致;
4、5 接收方發(fā)送 ACK 了,但是發(fā)送方還沒(méi)收到,有可能丟了,有可能還在路上;
6、7、8、9 肯定都發(fā)了,但是 8、9 已經(jīng)到了,6、7還沒(méi)打,出現(xiàn)了亂序,于是在緩存中存儲(chǔ),但是沒(méi)有返回 ACK。
????根據(jù)這個(gè)例子,我們可以知道,順序問(wèn)題和丟包問(wèn)題都有了能發(fā)送,所以我們先來(lái)看確認(rèn)與重發(fā)的機(jī)制。
????假設(shè) 4 的確認(rèn)到了,不幸的是,5 的 ACK 丟了,并且 6、7 的數(shù)據(jù)包也丟了,這時(shí)候會(huì)怎么處理呢?
????一種方法是超時(shí)重試,也就是對(duì)每一個(gè)發(fā)送了,但是沒(méi)有 ACK 的包,都有設(shè)一個(gè)定時(shí)器,一旦超過(guò)了一定的時(shí)間,就重新嘗試。這個(gè)超時(shí)時(shí)間不宜過(guò)短,時(shí)間必須大于往返時(shí)間 RTT,否則就會(huì)引起不必要的重傳也不宜過(guò)長(zhǎng),這樣超時(shí)時(shí)間變長(zhǎng),訪問(wèn)就變慢了。
????估計(jì)往返時(shí)間,需要 TCP 通過(guò)采樣 RTT 的時(shí)間,然后進(jìn)行加權(quán)平均,算出一個(gè)值,而且這個(gè)值還是要不斷變化的,因?yàn)榫W(wǎng)絡(luò)狀況不斷的變化。
????除了采樣 RTT,還要采樣 RTT 的波動(dòng)范圍,計(jì)算出一個(gè)估計(jì)的超時(shí)時(shí)間。由于重傳時(shí)間是不斷變化的,我們稱(chēng)為自適應(yīng)重傳算法(Adaptive Retransmission Algorithm)。
????如果過(guò)一段時(shí)間,5、6、7 都超時(shí)了,就會(huì)重新發(fā)送。接收方發(fā)現(xiàn) 5 原來(lái)接收過(guò),于是就丟棄5。收到了6,發(fā)送 ACK,要求下一個(gè)是 7,7 不幸又丟了。
????當(dāng) 7 再次超時(shí)的時(shí)候,如果有需要重傳,TCP 的策略就是超時(shí)間隔加倍。每當(dāng)遇到一次超時(shí)重傳的實(shí)時(shí),都會(huì)將下一次超時(shí)時(shí)間間隔設(shè)置為先前值的兩倍。兩次超時(shí),就說(shuō)明網(wǎng)絡(luò)環(huán)境差,不宜頻繁發(fā)送。
????可以看出,超時(shí)重發(fā)存在的問(wèn)題是,超時(shí)周期可能較長(zhǎng)。那是不是可以有更快的方式呢?
????有一個(gè)可以快速重傳的機(jī)制。當(dāng)接收方收到一個(gè)序號(hào)大于下一個(gè)所期望的報(bào)文段時(shí),就檢測(cè)到了數(shù)據(jù)流中的一個(gè)間格,于是發(fā)送三個(gè)冗余的ACK,客戶(hù)端收到后,就在定時(shí)器過(guò)期之前,重傳丟失的報(bào)文段。
????例如,接收方發(fā)現(xiàn) 6、8、9 都已經(jīng)接收了,但是 7 沒(méi)來(lái)。于是發(fā)送三個(gè) 6 的 ACK,要求下一個(gè)是 7??蛻?hù)端收到三個(gè),就會(huì)發(fā)現(xiàn) 7 的確丟了,不等超時(shí),就馬上重發(fā)。
????除此之外,還有一種方式稱(chēng)為 Selective Acknowledgment(SACK)。這種方式需要在 TCP 頭里加一個(gè) SACK 的東西,可以將緩存的地圖發(fā)格發(fā)送方。例如發(fā)送 ACK6、SACK8、SACK9,有了地圖,發(fā)送方一下子就能看出來(lái)是 7 丟了,然后快速重發(fā)。
流量控制問(wèn)題????接下來(lái),我們?cè)賮?lái)看看流量控制機(jī)制。在對(duì)于包的確認(rèn)中,會(huì)同時(shí)攜帶一個(gè)窗口大小的字段。
????我們先假設(shè)窗口不變的情況,發(fā)送端窗口始終為 9。4 的確認(rèn)來(lái)的時(shí)候,LastByteAcked 會(huì)右移一個(gè),這個(gè)時(shí)候,第 13 個(gè)包就可以發(fā)送了。
????這個(gè)時(shí)候,假設(shè)發(fā)送端發(fā)送過(guò)猛,將第三部分中的 10、11、12、13 全部發(fā)送,之后就停止發(fā)送,則此時(shí)未發(fā)送可發(fā)送部分為 0。
????當(dāng)對(duì)于包 5 的確認(rèn)到達(dá)的時(shí)候,在客戶(hù)端相當(dāng)于窗口再滑動(dòng)了一格,這個(gè)時(shí)候,才可以有更多的包可以發(fā)送了,例如第 14 個(gè)包才可以發(fā)送。
????如果接收方處理的太慢,導(dǎo)致緩存中沒(méi)有空間了,可以通過(guò)確認(rèn)信息修改窗口的大小,甚至可以設(shè)置為 0,則發(fā)送方將暫時(shí)停止發(fā)送。
????我們可以假設(shè)一個(gè)極端情況,接收端的應(yīng)用一直不讀取緩存中的數(shù)據(jù),當(dāng)數(shù)據(jù)包 6 確認(rèn)后,窗口大小就不會(huì)再是 9,而是減少一個(gè)變?yōu)榱?8。
????為什么會(huì)變?yōu)?8?你看,下圖中,當(dāng) 6 的確認(rèn)消息到達(dá)發(fā)送端的時(shí)候,左邊的 LastByteAcked 右移一位,而右邊的未發(fā)送可發(fā)送區(qū)域因?yàn)橐呀?jīng)變?yōu)?0,因此左邊的 LastByteSend 沒(méi)有移動(dòng),因此,窗口大小就從 9 變成了 8。
????而如果接收端一直不處理數(shù)據(jù),則隨著確認(rèn)的包越來(lái)越多,窗口越來(lái)越小,直到為 0。
????當(dāng)這個(gè)窗口大小通過(guò)包 14 的確認(rèn)到達(dá)發(fā)送端的時(shí)候,發(fā)送端的窗口也調(diào)整為 0,于是,發(fā)送端停止發(fā)送。
????當(dāng)發(fā)生這樣的情況時(shí),發(fā)送方會(huì)定時(shí)發(fā)送窗口探測(cè)數(shù)據(jù)包,看是否有機(jī)會(huì)調(diào)整窗口的大小。對(duì)于接收方來(lái)說(shuō),當(dāng)接收比較慢的時(shí)候,要防止低能窗口綜合征,別空出一個(gè)字節(jié)就趕緊告訴發(fā)送方,結(jié)果又被填滿了??梢栽诖翱谔〉臅r(shí)候,不更新窗口大小,直到達(dá)到一定大小,或者緩沖區(qū)一半為空,才更新窗口大小。
????這就是我們常說(shuō)的流量控制。
擁塞控制問(wèn)題????最后,我們來(lái)看一下?lián)砣刂频膯?wèn)題。
????這個(gè)問(wèn)題,也是靠窗口來(lái)解決的。前面的滑動(dòng)窗口 rwnd 是怕發(fā)送方把接收方緩存塞滿,而擁塞窗口 cwnd,是怕把網(wǎng)絡(luò)塞滿。
這里有一個(gè)公式:
LastByteSent - LastByteAcked <= min{cwnd, rwnd}
????可以看出,是擁塞窗口和滑動(dòng)窗口共同控制發(fā)送的速度。
????那發(fā)送方怎么判斷網(wǎng)絡(luò)是不是滿呢?這其實(shí)是個(gè)挺難的事情。因?yàn)閷?duì)于 TCP 協(xié)議來(lái)講,它壓根不知道整個(gè)網(wǎng)絡(luò)路徑都會(huì)經(jīng)歷什么。TCP 發(fā)送包常被比喻為往一個(gè)水管里灌水,而 TCP 的擁塞控制就是在不堵塞、不丟包的情況下,盡量發(fā)揮帶寬。
????水管有粗細(xì),網(wǎng)絡(luò)有帶寬,也就是每秒鐘能夠發(fā)送多少數(shù)據(jù);
水管有長(zhǎng)度,端到端有時(shí)延。在理想情況下:
水管里的水量 = 水管粗細(xì) x 水管長(zhǎng)度
而對(duì)于網(wǎng)絡(luò)來(lái)講:
通道的容量 = 帶寬 x 往返延遲
????如果我們?cè)O(shè)置發(fā)送窗口,使得發(fā)送但未確認(rèn)的包的數(shù)量為通道的容量,就能夠撐滿整個(gè)管道。
如上圖所示:
假設(shè)往返時(shí)間為 8s,去 4s,回 4s,每秒發(fā)送一個(gè)包,每個(gè)包 1024 byte。
????那么在 8s 后,就發(fā)出去了 8 個(gè)包。其中前 4 個(gè)包已經(jīng)到達(dá)接收端,但是 ACK 還沒(méi)有返回,不能算發(fā)送成功。而 5-8 后四個(gè)包還在路上,沒(méi)被接收。
這個(gè)時(shí)候,整個(gè)管道正好撐滿。在發(fā)送端,已發(fā)送未確認(rèn)的為 8 個(gè)包,也就是:
帶寬 = 1024byte/s x 8s(來(lái)回時(shí)間)
????如果我們?cè)谶@個(gè)基礎(chǔ)上再調(diào)大窗口,使得單位時(shí)間內(nèi)更多的包可以發(fā)送,會(huì)出現(xiàn)什么現(xiàn)象呢?
????原來(lái)發(fā)送一個(gè)包,從一端到另一端,假設(shè)一共經(jīng)過(guò)四個(gè)設(shè)備,每個(gè)設(shè)備處理一個(gè)包耗時(shí) 1s,所以到達(dá)另一端需要耗費(fèi) 4s。如果發(fā)送的更加快速,則單位時(shí)間內(nèi),會(huì)有更多的包到達(dá)這些中間設(shè)備,這些設(shè)備還是只能每秒處理一個(gè)包的話,多出來(lái)的包就會(huì)被丟棄,這不是我們希望看到的。
????這個(gè)時(shí)候,我們可以想其他的辦法。例如,這四個(gè)設(shè)備本來(lái)每秒處理一個(gè)包,但是我們?cè)谶@些設(shè)備上加緩存,處理不過(guò)來(lái)的就在隊(duì)列里面排著,這樣包就不會(huì)丟失,但是缺點(diǎn)也是顯而易見(jiàn)的,增加了時(shí)延。這個(gè)緩存的包,4s 肯定到達(dá)不了接收端,如果時(shí)延達(dá)到一定程度,就會(huì)超時(shí),這也不是我們希望看到的。
????針對(duì)上述兩種現(xiàn)象:包丟失和超時(shí)重傳。一旦出現(xiàn)了這些現(xiàn)象就說(shuō)明,發(fā)送速度太快了,要慢一點(diǎn)。但是一開(kāi)始,發(fā)送端怎么知道速度多快呢?怎么知道把窗口調(diào)整到合適大小呢?
????如果我們通過(guò)漏斗往瓶子里灌水,我們就知道,不能一桶水一下子全倒進(jìn)去,肯定會(huì)溢出來(lái)。一開(kāi)始要慢慢的倒,然后發(fā)現(xiàn)都能夠倒進(jìn)去,就加快速度。這叫做慢啟動(dòng)。
一個(gè) TCP 連接開(kāi)始
cwnd 設(shè)置為一個(gè)報(bào)文段,一次只能發(fā)送 1 個(gè);
當(dāng)收到這一個(gè)確認(rèn)的時(shí)候,cwnd 加 1,于是一次能夠發(fā)送 2 個(gè);
當(dāng)這兩個(gè)包的確認(rèn)到來(lái)的時(shí)候,每個(gè)確認(rèn)的 cwnd 加 1,兩個(gè)確認(rèn) cwnd 加 2,于是一次能夠發(fā)送 4 個(gè);
當(dāng)這四個(gè)的確認(rèn)到來(lái)的時(shí)候,每個(gè)確認(rèn) cwnd 加 1,四個(gè)確認(rèn) cwnd 加 4,于是一次能夠發(fā)送 8 個(gè)。
????從上面這個(gè)過(guò)程可以看出,這是指數(shù)性的增長(zhǎng)。
????但是漲到什么時(shí)候是個(gè)頭呢?一個(gè)值 ssthresh 為 65535 個(gè)字節(jié),當(dāng)超過(guò)這個(gè)值的時(shí)候,就會(huì)將將增長(zhǎng)速度降下來(lái)。
????此時(shí),每收到一個(gè)確認(rèn)后,cwnd 增加 1/cwnd。一次發(fā)送 8 個(gè),當(dāng) 8 個(gè)確認(rèn)到來(lái)的時(shí)候,每個(gè)確認(rèn)增加 1/8,8個(gè)確認(rèn)一共增加 1,于是一次就能夠發(fā)送 9 個(gè),變成了線性增長(zhǎng)。
????即使增長(zhǎng)變成了線性增長(zhǎng),還是會(huì)出現(xiàn)“溢出”的情況,出現(xiàn)擁塞。這時(shí)候一般就會(huì)直接降低倒水的速度,等待溢出的水慢慢滲透下去。
????擁塞的一種變現(xiàn)形式是丟包,需要超時(shí)重傳。這個(gè)時(shí)候,將 ssthresh 設(shè)為 cwnd/2,將 cwnd 設(shè)為 1,重新開(kāi)始慢啟動(dòng)。也就是,一旦超時(shí)重傳,馬上“從零開(kāi)始”。
????很明顯,這種方式太激進(jìn)了,將一個(gè)高速的傳輸速度一下子停了下來(lái),會(huì)造成網(wǎng)絡(luò)卡頓。
????前面有提過(guò)快速重傳算法。當(dāng)接收端發(fā)現(xiàn)丟了一個(gè)中間包的時(shí)候,發(fā)送三次前一個(gè)包的 ACK,告訴發(fā)送端要趕緊給我發(fā)下一個(gè)包,別等超時(shí)再重傳。TCP 認(rèn)為這種情況不嚴(yán)重,因?yàn)榇蟛糠譀](méi)丟,只丟了一小部分,cwnd 變?yōu)?cwnd/2,然后 sshthresh = cwnd。當(dāng)三個(gè)包返回的時(shí)候,cwnd = sshthresh + 3。
????可以看出這種情況下降速?zèng)]有那么激進(jìn),cwnd 還是在一個(gè)比較高的值,呈線性增長(zhǎng)。下圖是兩者的對(duì)比。
????就像前面說(shuō)的一樣,正是這種知進(jìn)退,使得時(shí)延在很重要的情況下,反而降低了速度。但是,我們仔細(xì)想一想,TCP 的擁塞控制主要用來(lái)避免的兩個(gè)現(xiàn)象都是有問(wèn)題的。
????第一個(gè)問(wèn)題是丟包。丟包并不一定表示通道滿了,也可能是管子本來(lái)就”漏水”。就像公網(wǎng)上帶寬不滿也會(huì)丟包,這個(gè)時(shí)候就認(rèn)為擁塞,而降低發(fā)送速度其實(shí)是不對(duì)的。
????第二個(gè)問(wèn)題是 TCP 的擁塞控制要等到將中間設(shè)備都填滿了,才發(fā)送丟包,從而降低速度。但其實(shí),這時(shí)候降低速度已經(jīng)晚了,在將管道填滿后,不應(yīng)該接著填,直到發(fā)生丟包才降速。
????為了優(yōu)化這兩個(gè)問(wèn)題,后來(lái)就有了 TCP BBR 擁塞算法。它企圖找到一個(gè)平衡點(diǎn),就是通過(guò)不斷的加快發(fā)送速度,將管道填滿,但是不要填滿中間設(shè)備的緩存,因?yàn)檫@樣時(shí)延會(huì)增加,在這個(gè)平衡點(diǎn)可以很好的達(dá)到高帶寬和低時(shí)延的平衡。
????下圖是 BBR 算法與普通 TCP 的對(duì)比:
小結(jié)順序問(wèn)題、丟包問(wèn)題、流量控制都是通過(guò)滑動(dòng)窗口來(lái)解決的。這就相當(dāng)于領(lǐng)導(dǎo)和員工的備忘錄,布置過(guò)的工作要有編號(hào),干完了有反饋,活不能派太多,也不能太少;
擁塞控制是通過(guò)擁塞窗口來(lái)解決的,相當(dāng)于往管道里面倒水,快了容易溢出,慢了浪費(fèi)帶寬,要摸著石頭過(guò)河,找到最優(yōu)值。
參考:
The TCP/IP Guide;
百度百科 - TCP詞條;
劉超 - 趣談網(wǎng)絡(luò)協(xié)議系列課;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/40245.html
摘要:收到了,發(fā)送,要求下一個(gè)是,不幸又丟了。在對(duì)于包的確認(rèn)中,會(huì)同時(shí)攜帶一個(gè)窗口大小的字段。前面的滑動(dòng)窗口是怕發(fā)送方把接收方緩存塞滿,而擁塞窗口,是怕把網(wǎng)絡(luò)塞滿。這里有一個(gè)公式可以看出,是擁塞窗口和滑動(dòng)窗口共同控制發(fā)送的速度。 網(wǎng)絡(luò)協(xié)議 1 - 概述 網(wǎng)絡(luò)協(xié)議 2 - IP 是怎么來(lái),又是怎么沒(méi)的? 網(wǎng)絡(luò)協(xié)議 3 - 從物理層到 MAC 層 網(wǎng)絡(luò)協(xié)議 4 - 交換機(jī)與 VLAN:辦公室太...
摘要:操作請(qǐng)求只能由啟動(dòng)器設(shè)備發(fā)起事件被響應(yīng)端設(shè)備用于把有關(guān)它狀態(tài)的改變通知啟動(dòng)器設(shè)備。會(huì)話將在啟動(dòng)器設(shè)備請(qǐng)求操作事務(wù)時(shí)被關(guān)閉,并且使用響應(yīng)端設(shè)備發(fā)出的一個(gè)有效響應(yīng)成功結(jié)束該請(qǐng)求。標(biāo)準(zhǔn)協(xié)議節(jié)斷開(kāi)事件。 歡迎關(guān)注公眾號(hào): nullobject 。文章首發(fā)在個(gè)人博客 https://www.nullobject.cn,公眾號(hào)nullobject同步更新。 PTP/IP (PTP over IP)...
閱讀 2814·2021-11-24 09:39
閱讀 2789·2021-09-23 11:45
閱讀 3414·2019-08-30 12:49
閱讀 3364·2019-08-30 11:18
閱讀 1930·2019-08-29 16:42
閱讀 3351·2019-08-29 16:35
閱讀 1332·2019-08-29 11:21
閱讀 1926·2019-08-26 13:49