日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

TCP 半連接隊列和全連接隊列滿了,怎么破?

作者 | 小林coding

來源 | 小林coding

責編 | 王曉曼

TCP 半連接隊列和全連接隊列滿了,怎么破?

前言

網(wǎng)上許多博客針對增大 TCP 半連接隊列和全連接隊列的方式如下:

  • 增大 TCP 半連接隊列方式是增大 tcp_max_syn_backlog;

  • 增大 TCP 全連接隊列方式是增大 listen 函數(shù)中的 backlog;

這里先跟大家說下,上面的方式都是不準確的。

“你怎么知道不準確?”

很簡單呀,因為我做了實驗和看了 TCP 協(xié)議棧的內(nèi)核源碼,發(fā)現(xiàn)要增大這兩個隊列長度,不是簡簡單單增大某一個參數(shù)就可以的。

接下來,就會以實戰(zhàn)+源碼分析,帶大家解密 TCP 半連接隊列和全連接隊列。

“源碼分析,那不是勸退嗎?我們搞 JAVA 的看不懂呀”

放心,本文的源碼分析不會涉及很深的知識,因為都被我刪減了,你只需要會條件判斷語句 if、左移右移操作符、加減法等基本語法,就可以看懂。

另外,不僅有源碼分析,還會介紹 linux 排查半連接隊列和全連接隊列的命令。

“哦?似乎很有看頭,那我姑且看一下吧!”

TCP 半連接隊列和全連接隊列滿了,怎么破?

什么是 TCP 半連接隊列和全連接隊列?

在 TCP 三次握手的時候,Linux 內(nèi)核會維護兩個隊列,分別是:

  • 半連接隊列,也稱 SYN 隊列;

  • 全連接隊列,也稱 accepet 隊列;

服務端收到客戶端發(fā)起的 SYN 請求后,內(nèi)核會把該連接存儲到半連接隊列,并向客戶端響應 SYN+ACK,接著客戶端會返回 ACK,服務端收到第三次握手的 ACK 后,內(nèi)核會把連接從半連接隊列移除,然后創(chuàng)建新的完全的連接,并將其添加到 accept 隊列,等待進程調(diào)用 accept 函數(shù)時把連接取出來

TCP 半連接隊列和全連接隊列滿了,怎么破?

半連接隊列與全連接隊列

不管是半連接隊列還是全連接隊列,都有最大長度限制,超過限制時,內(nèi)核會直接丟棄,或返回 RST 包。

TCP 半連接隊列和全連接隊列滿了,怎么破?

實戰(zhàn) - TCP 全連接隊列溢出

1、如何知道應用程序的 TCP 全連接隊列大小?

在服務端可以使用 ss 命令,來查看 TCP 全連接隊列的情況:

但需要注意的是 ss 命令獲取的 Recv-Q/Send-Q 在「LISTEN 狀態(tài)」和「非 LISTEN 狀態(tài)」所表達的含義是不同的。從下面的內(nèi)核代碼可以看出區(qū)別:

TCP 半連接隊列和全連接隊列滿了,怎么破?

在「LISTEN 狀態(tài)」時,Recv-Q/Send-Q 表示的含義如下:

TCP 半連接隊列和全連接隊列滿了,怎么破?
  • Recv-Q:當前全連接隊列的大小,也就是當前已完成三次握手并等待服務端accept 的 TCP 連接個數(shù);

  • Send-Q:當前全連接最大隊列長度,上面的輸出結果說明監(jiān)聽 8088 端口的 TCP 服務進程,最大全連接長度為 128;

在「非 LISTEN 狀態(tài)」時,Recv-Q/Send-Q 表示的含義如下:

TCP 半連接隊列和全連接隊列滿了,怎么破?
  • Recv-Q:已收到但未被應用進程讀取的字節(jié)數(shù);

  • Send-Q:已發(fā)送但未收到確認的字節(jié)數(shù);

2、如何模擬 TCP 全連接隊列溢出的場景?

TCP 半連接隊列和全連接隊列滿了,怎么破?

測試環(huán)境

實驗環(huán)境:

  • 客戶端和服務端都是 centos 6.5 ,Linux 內(nèi)核版本 2.6.32

  • 服務端 IP 192.168.3.200,客戶端 IP 192.168.3.100

  • 服務端是 Nginx 服務,端口為 8088

這里先介紹下 wrk 工具,它是一款簡單的 HTTP 壓測工具,它能夠在單機多核 CPU 的條件下,使用系統(tǒng)自帶的高性能 I/O 機制,通過多線程和事件模式,對目標機器產(chǎn)生大量的負載。

本次模擬實驗就使用 wrk 工具來壓力測試服務端,發(fā)起大量的請求,一起看看服務端 TCP 全連接隊列滿了會發(fā)生什么?有什么觀察指標?

客戶端執(zhí)行 wrk 命令對服務端發(fā)起壓力測試,并發(fā) 3 萬個連接:

TCP 半連接隊列和全連接隊列滿了,怎么破?

在服務端可以使用 ss 命令,來查看當前 TCP 全連接隊列的情況:

TCP 半連接隊列和全連接隊列滿了,怎么破?

其間共執(zhí)行了兩次 ss 命令,從上面的輸出結果,可以發(fā)現(xiàn)當前 TCP 全連接隊列上升到了 129 大小,超過了最大 TCP 全連接隊列。

當超過了 TCP 最大全連接隊列,服務端則會丟掉后續(xù)進來的 TCP 連接,丟掉的 TCP 連接的個數(shù)會被統(tǒng)計起來,我們可以使用 netstat -s 命令來查看:

TCP 半連接隊列和全連接隊列滿了,怎么破?

上面看到的 41150 times ,表示全連接隊列溢出的次數(shù),注意這個是累計值。可以隔幾秒鐘執(zhí)行下,如果這個數(shù)字一直在增加的話肯定全連接隊列偶爾滿了。

從上面的模擬結果,可以得知,當服務端并發(fā)處理大量請求時,如果 TCP 全連接隊列過小,就容易溢出。發(fā)生 TCP 全連接隊溢出的時候,后續(xù)的請求就會被丟棄,這樣就會出現(xiàn)服務端請求數(shù)量上不去的現(xiàn)象。

TCP 半連接隊列和全連接隊列滿了,怎么破?

全連接隊列溢出

3、全連接隊列滿了,就只會丟棄連接嗎?

實際上,丟棄連接只是 Linux 的默認行為,我們還可以選擇向客戶端發(fā)送 RST 復位報文,告訴客戶端連接已經(jīng)建立失敗。

TCP 半連接隊列和全連接隊列滿了,怎么破?

tcp_abort_on_overflow 共有兩個值分別是 0 和 1,其分別表示:

  • 0 :表示如果全連接隊列滿了,那么 server 扔掉 client 發(fā)過來的 ack ;

  • 1 :表示如果全連接隊列滿了,那么 server 發(fā)送一個 reset 包給 client,表示廢掉這個握手過程和這個連接;

如果要想知道客戶端連接不上服務端,是不是服務端 TCP 全連接隊列滿的原因,那么可以把 tcp_abort_on_overflow 設置為 1,這時如果在客戶端異常中可以看到很多 connection reset by peer 的錯誤,那么就可以證明是由于服務端 TCP 全連接隊列溢出的問題。

通常情況下,應當把 tcp_abort_on_overflow 設置為 0,因為這樣更有利于應對突發(fā)流量。

舉個例子,當 TCP 全連接隊列滿導致服務器丟掉了 ACK,與此同時,客戶端的連接狀態(tài)卻是 ESTABLISHED,進程就在建立好的連接上發(fā)送請求。只要服務器沒有為請求回復 ACK,請求就會被多次重發(fā)。如果服務器上的進程只是短暫的繁忙造成 accept 隊列滿,那么當 TCP 全連接隊列有空位時,再次接收到的請求報文由于含有 ACK,仍然會觸發(fā)服務器端成功建立連接

所以,tcp_abort_on_overflow 設為 0 可以提高連接建立的成功率,只有你非常肯定 TCP 全連接隊列會長期溢出時,才能設置為 1 以盡快通知客戶端。

4、如何增大 TCP 全連接隊列呢?

是的,當發(fā)現(xiàn) TCP 全連接隊列發(fā)生溢出的時候,我們就需要增大該隊列的大小,以便可以應對客戶端大量的請求。

TCP 全連接隊列足最大值取決于 somaxconn 和 backlog 之間的最小值,也就是 min(somaxconn, backlog)。從下面的 Linux 內(nèi)核代碼可以得知:

TCP 半連接隊列和全連接隊列滿了,怎么破?
  • somaxconn 是 Linux 內(nèi)核的參數(shù),默認值是 128,可以通過
    /proc/sys/net/core/somaxconn 來設置其值;

  • backlog 是 listen(int sockfd, int backlog) 函數(shù)中的 backlog 大小,Nginx 默認值是 511,可以通過修改配置文件設置其長度;

前面模擬測試中,我的測試環(huán)境:

  • somaxconn 是默認值 128;

  • Nginx 的 backlog 是默認值 511

所以測試環(huán)境的 TCP 全連接隊列最大值為 min(128, 511),也就是 128,可以執(zhí)行ss 命令查看:

TCP 半連接隊列和全連接隊列滿了,怎么破?

現(xiàn)在我們重新壓測,把 TCP 全連接隊列搞大,把 somaxconn 設置成 5000:

TCP 半連接隊列和全連接隊列滿了,怎么破?

接著把 Nginx 的 backlog 也同樣設置成 5000:

TCP 半連接隊列和全連接隊列滿了,怎么破?

最后要重啟 Nginx 服務,因為只有重新調(diào)用 listen 函數(shù), TCP 全連接隊列才會重新初始化。

重啟完后 Nginx 服務后,服務端執(zhí)行 ss 命令,查看 TCP 全連接隊列大小:

TCP 半連接隊列和全連接隊列滿了,怎么破?

從執(zhí)行結果,可以發(fā)現(xiàn) TCP 全連接最大值為 5000。

5、增大 TCP 全連接隊列后,繼續(xù)壓測

客戶端同樣以 3 萬個連接并發(fā)發(fā)送請求給服務端:

服務端執(zhí)行 ss 命令,查看 TCP 全連接隊列使用情況:

TCP 半連接隊列和全連接隊列滿了,怎么破?

從上面的執(zhí)行結果,可以發(fā)現(xiàn)全連接隊列使用增長的很快,但是一直都沒有超過最大值,所以就不會溢出,那么 netstat -s 就不會有 TCP 全連接隊列溢出個數(shù)的顯示:

TCP 半連接隊列和全連接隊列滿了,怎么破?

說明 TCP 全連接隊列最大值從 128 增大到 5000 后,服務端抗住了 3 萬連接并發(fā)請求,也沒有發(fā)生全連接隊列溢出的現(xiàn)象了。

如果持續(xù)不斷地有連接因為 TCP 全連接隊列溢出被丟棄,就應該調(diào)大 backlog 以及 somaxconn 參數(shù)。

TCP 半連接隊列和全連接隊列滿了,怎么破?

實戰(zhàn) - TCP 半連接隊列溢出

1、如何查看 TCP 半連接隊列長度?

很遺憾,TCP 半連接隊列長度的長度,沒有像全連接隊列那樣可以用 ss 命令查看。

但是我們可以抓住 TCP 半連接的特點,就是服務端處于 SYN_RECV 狀態(tài)的 TCP 連接,就是在 TCP 半連接隊列。

于是,我們可以使用如下命令計算當前 TCP 半連接隊列長度:

TCP 半連接隊列和全連接隊列滿了,怎么破?

2、如何模擬 TCP 半連接隊列溢出場景?

模擬 TCP 半連接溢出場景不難,實際上就是對服務端一直發(fā)送 TCP SYN 包,但是不回第三次握手 ACK,這樣就會使得服務端有大量的處于 SYN_RECV 狀態(tài)的 TCP 連接。

這其實也就是所謂的 SYN 洪泛、SYN 攻擊、DDoS 攻擊。

TCP 半連接隊列和全連接隊列滿了,怎么破?

測試環(huán)境

實驗環(huán)境:

  • 客戶端和服務端都是 CentOs 6.5 ,Linux 內(nèi)核版本 2.6.32

  • 服務端 IP 192.168.3.200,客戶端 IP 192.168.3.100

  • 服務端是 Nginx 服務,端口為 8088

注意:本次模擬實驗是沒有開啟 tcp_syncookies,關于 tcp_syncookies 的作用,后續(xù)會說明。

本次實驗使用 hping3 工具模擬 SYN 攻擊:

TCP 半連接隊列和全連接隊列滿了,怎么破?

當服務端受到 SYN 攻擊后,連接服務端 ssh 就會斷開了,無法再連上。只能在服務端主機上執(zhí)行查看當前 TCP 半連接隊列大小:

TCP 半連接隊列和全連接隊列滿了,怎么破?

同時,還可以通過 netstat -s 觀察半連接隊列溢出的情況:

TCP 半連接隊列和全連接隊列滿了,怎么破?

上面輸出的數(shù)值是累計值,表示共有多少個 TCP 連接因為半連接隊列溢出而被丟棄。隔幾秒執(zhí)行幾次,如果有上升的趨勢,說明當前存在半連接隊列溢出的現(xiàn)象。3、大部分人都說 tcp_max_syn_backlog 是指定半連接隊列的大小,是真的嗎?

很遺憾,半連接隊列的大小并不單單只跟 tcp_max_syn_backlog 有關系。

上面模擬 SYN 攻擊場景時,服務端的 tcp_max_syn_backlog 的默認值如下:

TCP 半連接隊列和全連接隊列滿了,怎么破?

但是在測試的時候發(fā)現(xiàn),服務端最多只有 256 個半連接隊列,而不是 512,所以半連接隊列的最大長度不一定由 tcp_max_syn_backlog 值決定的4、走進 Linux 內(nèi)核的源碼,來分析 TCP 半連接隊列的最大值是如何決定的。

TCP 第一次握手(收到 SYN 包)的 Linux 內(nèi)核代碼如下,其中縮減了大量的代碼,只需要重點關注 TCP 半連接隊列溢出的處理邏輯:

TCP 半連接隊列和全連接隊列滿了,怎么破?

從源碼中,我可以得出共有三個條件因隊列長度的關系而被丟棄的:

TCP 半連接隊列和全連接隊列滿了,怎么破?
  • 如果半連接隊列滿了,并且沒有開啟 tcp_syncookies,則會丟棄;

  • 若全連接隊列滿了,且沒有重傳 SYN+ACK 包的連接請求多于 1 個,則會丟棄;

  • 如果沒有開啟 tcp_syncookies,并且 max_syn_backlog 減去 當前半連接隊列長度小于 (max_syn_backlog >> 2),則會丟棄;

關于 tcp_syncookies 的設置,后面在詳細說明,可以先給大家說一下,開啟 tcp_syncookies 是緩解 SYN 攻擊其中一個手段。

接下來,我們繼續(xù)跟一下檢測半連接隊列是否滿的函數(shù)
inet_csk_reqsk_queue_is_full 和 檢測全連接隊列是否滿的函數(shù) sk_acceptq_is_full :

TCP 半連接隊列和全連接隊列滿了,怎么破?

從上面源碼,可以得知:

  • 全連接隊列的最大值是 sk_max_ack_backlog 變量,sk_max_ack_backlog 實際上是在 listen 源碼里指定的,也就是 min(somaxconn, backlog);

  • 半連接隊列的最大值是 max_qlen_log 變量,max_qlen_log 是在哪指定的呢?現(xiàn)在暫時還不知道,我們繼續(xù)跟進;

我們繼續(xù)跟進代碼,看一下是哪里初始化了半連接隊列的最大值 max_qlen_log:

TCP 半連接隊列和全連接隊列滿了,怎么破?

從上面的代碼中,我們可以算出 max_qlen_log 是 8,于是代入到 檢測半連接隊列是否滿的函數(shù) reqsk_queue_is_full :

TCP 半連接隊列和全連接隊列滿了,怎么破?

也就是 qlen >> 8 什么時候為 1 就代表半連接隊列滿了。這計算并不難,很明顯是當 qlen 為 256 時,256 >> 8 = 1。

至此,總算知道為什么上面模擬測試 SYN 攻擊的時候,服務端處于 SYN_RECV 連接最大只有 256 個。

可見,半連接隊列最大值不是單單由 max_syn_backlog 決定,還跟 somaxconn 和 backlog 有關系

在 Linux 2.6.32 內(nèi)核版本,它們之間的關系,總體可以概況為:

TCP 半連接隊列和全連接隊列滿了,怎么破?
  • 當 max_syn_backlog > min(somaxconn, backlog) 時, 半連接隊列最大值 max_qlen_log = min(somaxconn, backlog) * 2;

  • 當 max_syn_backlog < min(somaxconn, backlog) 時, 半連接隊列最大值 max_qlen_log = max_syn_backlog * 2;

5、半連接隊列最大值 max_qlen_log 就表示服務端處于 SYN_REVC 狀態(tài)的最大個數(shù)嗎?

依然很遺憾,并不是。

max_qlen_log 是理論半連接隊列最大值,并不一定代表服務端處于 SYN_REVC 狀態(tài)的最大個數(shù)。

在前面我們在分析 TCP 第一次握手(收到 SYN 包)時會被丟棄的三種條件:

  • 如果半連接隊列滿了,并且沒有開啟 tcp_syncookies,則會丟棄;

  • 若全連接隊列滿了,且沒有重傳 SYN+ACK 包的連接請求多于 1 個,則會丟棄;

  • 如果沒有開啟 tcp_syncookies,并且 max_syn_backlog 減去 當前半連接隊列長度小于 (max_syn_backlog >> 2),則會丟棄;

假設條件1當前半連接隊列的長度 「沒有超過」理論的半連接隊列最大值 max_qlen_log,那么如果條件 3 成立,則依然會丟棄 SYN 包,也就會使得服務端處于 SYN_REVC 狀態(tài)的最大個數(shù)不會是理論值 max_qlen_log。

似乎很難理解,我們繼續(xù)接著做實驗,實驗見真知。

服務端環(huán)境如下:

TCP 半連接隊列和全連接隊列滿了,怎么破?

配置完后,服務端要重啟 Nginx,因為全連接隊列最大和半連接隊列最大值是在 listen 函數(shù)初始化。

根據(jù)前面的源碼分析,我們可以計算出半連接隊列 max_qlen_log 的最大值為 256:

TCP 半連接隊列和全連接隊列滿了,怎么破?

客戶端執(zhí)行 hping3 發(fā)起 SYN 攻擊:

TCP 半連接隊列和全連接隊列滿了,怎么破?

服務端執(zhí)行如下命令,查看處于 SYN_RECV 狀態(tài)的最大個數(shù):

TCP 半連接隊列和全連接隊列滿了,怎么破?

可以發(fā)現(xiàn),服務端處于 SYN_RECV 狀態(tài)的最大個數(shù)并不是 max_qlen_log 變量的值。

這就是前面所說的原因:如果當前半連接隊列的長度 「沒有超過」理論半連接隊列最大值 max_qlen_log,那么如果條件 3 成立,則依然會丟棄 SYN 包,也就會使得服務端處于 SYN_REVC 狀態(tài)的最大個數(shù)不會是理論值 max_qlen_log。

我們來分析一波條件 3 :

TCP 半連接隊列和全連接隊列滿了,怎么破?

從上面的分析,可以得知如果觸發(fā)「當前半連接隊列長度 > 192」條件,TCP 第一次握手的 SYN 包是會被丟棄的。

在前面我們測試的結果,服務端處于 SYN_RECV 狀態(tài)的最大個數(shù)是 193,正好是觸發(fā)了條件 3,所以處于 SYN_RECV 狀態(tài)的個數(shù)還沒到「理論半連接隊列最大值 256」,就已經(jīng)把 SYN 包丟棄了。

所以,服務端處于 SYN_RECV 狀態(tài)的最大個數(shù)分為如下兩種情況:

  • 如果「當前半連接隊列」沒超過「理論半連接隊列最大值」,但是超過 max_syn_backlog - (max_syn_backlog >> 2),那么處于 SYN_RECV 狀態(tài)的最大個數(shù)就是 max_syn_backlog - (max_syn_backlog >> 2);

  • 如果「當前半連接隊列」超過「理論半連接隊列最大值」,那么處于 SYN_RECV 狀態(tài)的最大個數(shù)就是「理論半連接隊列最大值」;

6、每個 Linux 內(nèi)核版本「理論」半連接最大值計算方式會不同。

在上面我們是針對 Linux 2.6.32 版本分析的「理論」半連接最大值的算法,可能每個版本有些不同。

比如在 Linux 5.0.0 的時候,「理論」半連接最大值就是全連接隊列最大值,但依然還是有隊列溢出的三個條件:

TCP 半連接隊列和全連接隊列滿了,怎么破?

7、如果 SYN 半連接隊列已滿,只能丟棄連接嗎?并不是這樣,開啟 syncookies 功能就可以在不使用 SYN 半連接隊列的情況下成功建立連接,在前面我們源碼分析也可以看到這點,當開啟了 syncookies 功能就不會丟棄連接。

syncookies 是這么做的:服務器根據(jù)當前狀態(tài)計算出一個值,放在己方發(fā)出的 SYN+ACK 報文中發(fā)出,當客戶端返回 ACK 報文時,取出該值驗證,如果合法,就認為連接建立成功,如下圖所示。

TCP 半連接隊列和全連接隊列滿了,怎么破?

開啟 syncookies 功能

syncookies 參數(shù)主要有以下三個值:

  • 0 值,表示關閉該功能;

  • 1 值,表示僅當 SYN 半連接隊列放不下時,再啟用它;

  • 2 值,表示無條件開啟功能;

那么在應對 SYN 攻擊時,只需要設置為 1 即可:

TCP 半連接隊列和全連接隊列滿了,怎么破?

8、如何防御 SYN 攻擊?

這里給出幾種防御 SYN 攻擊的方法:

  • 增大半連接隊列;

  • 開啟 tcp_syncookies 功能;

  • 減少 SYN+ACK 重傳次數(shù)。

(1)方式一:增大半連接隊列在前面源碼和實驗中,得知要想增大半連接隊列,我們得知不能只單純增大 tcp_max_syn_backlog 的值,還需一同增大 somaxconn 和 backlog,也就是增大全連接隊列。否則,只單純增大 tcp_max_syn_backlog 是無效的。

增大 tcp_max_syn_backlog 和 somaxconn 的方法是修改 Linux 內(nèi)核參數(shù):

TCP 半連接隊列和全連接隊列滿了,怎么破?

增大 backlog 的方式,每個 Web 服務都不同,比如 Nginx 增大 backlog 的方法如下:

TCP 半連接隊列和全連接隊列滿了,怎么破?

最后,改變了如上這些參數(shù)后,要重啟 Nginx 服務,因為半連接隊列和全連接隊列都是在 listen 初始化的。

(2)方式二:開啟 tcp_syncookies 功能

開啟 tcp_syncookies 功能的方式也很簡單,修改 Linux 內(nèi)核參數(shù):

(3)方式三:減少 SYN+ACK 重傳次數(shù)

當服務端受到 SYN 攻擊時,就會有大量處于 SYN_REVC 狀態(tài)的 TCP 連接,處于這個狀態(tài)的 TCP 會重傳 SYN+ACK ,當重傳超過次數(shù)達到上限后,就會斷開連接。

那么針對 SYN 攻擊的場景,我們可以減少 SYN+ACK 的重傳次數(shù),以加快處于 SYN_REVC 狀態(tài)的 TCP 連接斷開。

TCP 半連接隊列和全連接隊列滿了,怎么破?

參考:

[1] 系統(tǒng)性能調(diào)優(yōu)必知必會.陶輝.極客時間.

[2] https://blog.cloudflare.com/syn-packet-handling-in-the-wild

分享到:
標簽:TCP
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定