亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Go 在游戲行業中的工程實踐

2019-11-09 15:04:46
字體:
來源:轉載
供稿:網友

先從工程說起

軟件工程三要素

我創業后,總結了過往工作和創業過程中參與的項目,發現不論做什么,軟件工程都回到三個問題上: 需求。首先,我們會有一個方向。 時間。大概多長時間做完,需求和時間是關聯的。 資源。我們打算投入的人才類型、人才數量、資金數量、資金能夠支撐團隊運轉多久。

這三者互相影響。所以,我們在做軟件工程時,所有的決策都逃不開這三個因素。區別可能僅僅是當我想做一個小程序,不指望長期地更新它時,代碼可能很簡單。但如果今天要做一個需要長期更新的游戲,比如當預計更新時間需要一兩年時,就不可能隨便地定義很簡單、很初級的規范,因為這樣的東西沒有辦法長久維持。但是從公司經營的角度看,往往會考慮資金預算,因為時間資源都是有限的。所以,我所有的決策都會落到這三個因素上。

游戲行業的軟件工程

為了大家更好的理解我的決定,下面和大家分享一下游戲行業的軟件工程存在的一些問題:

需求不確定性很大 產品設計人員和開發人員的最大矛盾在于需求不確定。如果今天產品設計人員說:“我要做這個東西,需求不會改變?!蹦敲矗蚁嘈琶恳粋€開發人員都會非常高興。通常會有時間節點的要求 游戲往往會有時間節點的安排,比如臨近一些長假,大家回老家后會減少玩游戲的時間,此時,你需要通過運營活動增加用戶留存。它有時間節點性,譬如運營商今天已經約好廣告,幾點幾分開始導量,那么這個行為會影響游戲的增長,所以服務器、版本等都要做好準備,因為不能出現問題。另外,國內游戲普遍存在山寨的問題,但其實山寨也要講究戰術,假如大家都山寨,那么你為了搶占市場先機,必須快速上線。如果是做創意型的游戲,可能需求變動比較大,如果是做創意較低的游戲,時間的要求則會很高。穩定性和實時性要求雙高 導量等都是流量變現的生意,稍微有一點折損,回報率就不同。就像剛才的分享,它很精細地去摳用戶的到達率,中間下載到底卡在哪個點。其實游戲的穩定性和實時性要求都非常高,大家都玩過游戲,特別是聯網型游戲很卡,會造成用戶體驗很差。網站中,單個頁面展示 0.5 s 和 2 s 沒有太大差異,但是一款游戲里的操作差到秒級時,用戶就會開罵。另外,游戲中玩家的數據很寶貴,因為這些數據是玩家花錢花時間去獲得的,所以數據安全性要求特別高。人員普遍缺乏工程經驗 參與的人員普遍缺乏工程經驗,比較常聽到的是“我原來做 xx 領域,現在有興趣做游戲,就加入游戲行業了。”另外,大部分產品項目都是默默無聞的,上線后沒有大量的用戶就會消失,大家平時能看到的是極少數,這就是行業現狀。我們作為一個公司,沒有辦法把自己放在一個“這個游戲肯定賺錢,我們的人員素質都很高,我們的需求都非常確定”的角度,我們只能做最壞、最保險的打算。因此,我們會比較現實、客觀地剖析所處的環境。

保持簡單

在這種環境下,我們所能做的只有一件事情:保持簡單。保持簡單有很多好處: 1. 門檻低、參與人員要求不高; 2. 做起來快; 3. 驗證快,當需求不確定的時候,盡早去驗證,就可以盡早調整它; 4. 迭代快,可以快速地調整; 5. 簡單的事情容易說清楚,不容易在溝通中出現誤差,比如今天想要做一個東西或者制定一個項目的規范,如果列出手冊讓程序員按照手冊進行編碼,相信很多人其實根本不會去看; 6. 不容易出錯; 7. 出錯了也比較容易找到問題的原因。

把事情做復雜了容易,做簡單卻比較難。我在團隊中一直鼓勵大家盡量采用簡單的方式實現。

我采取的策略

自動影射數據庫的緩存系統游戲的穩定性和實時性要求雙高。當我扔一個 Redis 給大家,業務就往 Redis 訪問,數據落地,寫到 MySQL。如此無法保證所有人產出一樣質量的設計方式,在小團隊中的風險很大。所以,我做了數據庫的自動映射,開發的時候只需要與 MySQL 打交道,剩下的事情都交給框架去做,開發的難度就大幅下降,只要你懂得用這套系統,基本上開發出來的程序不會有效率問題,大家的精力就可以放在業務的開發上,不用再去糾結緩存中具體要用什么數據結構去組織、數據要用什么樣的方式同步等。

貫徹速錯理念讓程序員以簡潔的方式開發業務邏輯,開發的時候只管做正確的事情,錯誤的東西我不需要去增加代碼的復雜度。速錯讓我們比較早地暴露問題。

簡單的業務模塊管理用一句話就能說清楚的管理方式,稍后也會跟大家分享。

錯誤和異常處理

Go 和其他編程語言不太一樣的是,它把錯誤和異常分開。Go 提供了 error 類型用來表達錯誤,語法上允許函數有多個返回值,因此,返回 error 的設計在 runtime 中隨處可見。另外,由于 Go 的普及率不高,所以我列一下代碼(如圖 1,2 所示),與大家分享一下 Go 的錯誤寫法。 圖 1

這個函數是兩個偶數相加,如果參數不是偶數的話,就會返回一個 error,error 這個包是 Go 內置的,可以讓你快速返回一個錯誤,不需要重新手動構造錯誤類型。圖 2

調用它的時候可以通過第二個參數是否 nil 來判斷它是否出錯,然后把對應的錯誤信息打印出來。

錯誤處理

有時候只是判斷 nil 是不夠的,因為有時會有不同的錯誤類型,我們要針對不同的錯誤類型來判斷,有時候錯誤中需要附帶額外的錯誤信息。 有兩種常見的做法: 1. 設置一個全局變量,業務上直接返回全局變量,外部調用時可以判斷返回的 error 是不是這個全局變量,因為 error 是引用類型,所以可以通過判斷引用來判斷是不是某個錯誤。這種方式在平時用的比較多。 2. 自己去實現 error 接口,這樣可以附帶更詳細的數據和信息,外部就能取到具體的上下文相關信息。這個做法相對更復雜。

異常

運行時拋出:數組越界、空對象、類型斷言失敗。 panic() 手動拋出。它的參數是可以任何類型的,函數就不用顯示去返回一個 error。 defer() + recover()。 不捕獲進程就會退出。

速錯實踐

只處理業務上定義的錯誤,不做多余的事。

圖 3

以裝備強化(如圖 3 所示)為例,如果我們沒有實踐出錯,那一個裝備強化的代碼邏輯可能是好幾個 if,如數據是否存在等。

圖 4

如圖 4 所示,如果是速錯的寫法,在我們項目中會定義一個 fatal.when。如果判斷這句話是錯誤,則會出現 panic。數組訪問時不會去額外判斷數組長度,因為正常的客戶端知道數組長度,如果返回越界,則定義為客戶端 BUG 或者非法客戶端。另外,數據是否存在也不用管,因為如果訪問的時候發現是空對象,它就會拋出來。所以有兩個前提,只有錯誤的客戶端邏輯才會觸發 fatal 和 panic,我們不必為外掛開發者提供友好的錯誤提示,像這種程序錯誤,我們內部會計入日志,沒有必要反饋給客戶端。

分清會話級別的異常和業務級別的異常。 游戲其實有兩種可能的異常情況: a. 會話級別的異常。單個玩家操作某個東西,比如剛才的強化,它可能存在客戶端 Bug。玩家點進去時,鏈接就會斷開,我們把這種常見的錯誤異常定義為會話級別的異常,它只影響自己、不影響別人。 b. 業務級別的異常。假設我們有一個玩家在線 PK 匹配系統,假設這個匹配系統的進程因為某一段代碼寫錯掛掉,速度越界,這時業務是沒有辦法響應所有人請求。此時,我們會直接讓進程掛掉,因為業務已經無法響應。因此,業務進程的異常會影響所有人。

所有 goroutine 都應有明確的入口。

所有入口都應有 recover 和日志記錄。

繪畫入口只記錄日志,不拋出異常。

業務入口記錄日志后,拋出異常讓進程崩潰。 如果不及時讓進程掛掉,它可能會產生更嚴重的問題。早期用 php 做頁游的時候就遇到這種情況,其實某一段業務邏輯 PHP 執行已經出錯,同時把緩存污染。但是,我們的做法并沒有直接把這個問題暴露出來,而玩家在已經污染的緩存數據下面跑,數據會越壞越嚴重,等到玩家向我們反饋他的數據壞掉時,我們已經無法還原,這種問題很讓人頭痛,因此,我們傾向于在出現問題后,第一時間暴露出來,而不是把它掩蓋掉。

實踐總結

需要讓用戶做出響應的錯誤才需要管。假設我有一個系統,系統告訴玩家他目前余額不足,需要進行充值。余額不足這件事就屬于業務上已經定義好需要對應去處理的一個情況,這種就屬于業務上面的錯誤,不屬于程序的錯誤或者異常。

模塊調用者是模塊開發者的用戶。 我們平時做的時候不只是把東西交付給最終用戶。其實,我們平時在開發的時候,兩個模塊互相也是用戶關系。那么,我需不需要讓調用者知道這個事情,然后由他做出對應處理?如果不需要,則不需要有多余的錯誤判斷和錯誤反饋。

客戶端開發者是服務端開發者的用戶。 服務端的信息是不是需要客戶端處理?比如,玩家的網絡連接故障,那么客戶端需要趕快彈出一個界面“我現在正在重連”。此時,錯誤需要暴露給客戶端,并且去判斷處理。否則,有一些游戲沒有斷線重連機制,斷掉就是斷掉,那么此時應該暴露,而不是掩蓋。

服務端開發者是自己的用戶。 如果錯誤沒有處理好,最后坑的是自己。如果服務端的錯誤處理沒有寫好、客戶信息處理不全,可能最后會增加自己查問題的難度。 所以,我的總結關鍵是第 1 條,需要讓用戶做出響應的才需要管,不需要響應的不需要做多余判斷。這樣程序不需要寫很多錯誤判斷,其實大部分的錯誤是直接當異常處理掉。因為,我們在定義業務時,通常不會定義數據庫故障時怎么樣、網絡連接故障時怎么樣、通信協議故障時怎么樣,通常需求不會到這種級別。因此,這種情況我們當異常處理。

interface 的應用

interface 是 Go 的核心

大家可能更多的是聽到 Go 在并發方面的特性,其實 Go 在面向對象方面,跟其他的語言也有很大差異。我認為 interface 在 Go 里面非常重要,如果沒有正確理解 interface,那么 Go 就沒有被正確理解。

interface 有兩個很重要的特性: 1. 它的實現是隱式的; 2. interface可以組合出來。 圖 5

如圖 5 所示,interface 的實現是隱式的特點,可能在工程實踐中會引發一些問題。如看到這個類型時,不知道這個類型具體實現了哪些接口。有一個小技巧是通過匿名的全局變量,做一個類型轉換,這樣在編譯時期就能暴露問題,如果 MyImplement 沒有實現 MyInterface,那么編譯就無法實現。比較常見的誤解是,MyImplement 前面有個星號,這是它的指針類型,這個方法是實現在這個結構體的指針類型上的。調用時,有些地方可能不小心會寫成結構體類型,然后就會出現編譯失敗。因為,結構體和結構體指針是不一樣的。

io 包是最好的示例

io 包定義了實現 io 所需的基本接口(譬如讀、寫、關閉)。通過基本接口組裝出不同的復合型接口 (譬如,同時支持讀寫的 io,和同時支持讀寫關閉的 io)。舉例,Reader Writer Closer 分別是 3 個接口。如果某個 io 是只讀,就只需要實現 Reader,如果某個 io 是只寫,就只需要實現 Writer ,有一些 io 是不可關閉的,不一定可以實現 Closer,所以這三個是分開的。這三個最基本 interface 又可以重新組裝,這是 Go 很重要的一個特性。另外,在 os 包中就實現了文件 io,net 包實現了網絡 io,bytes 包實現了內存 io,bufio 包實現了帶緩存的 io,bufio 包利用接口解耦了底層 io 實現。

依賴注入

業務模塊不像 runtime,交叉引用很常見。但 Go 不允許 package 之間交叉引用。所以我們需要換一種思路,業務模塊只要聲明它想要什么,要的東西從哪里來不用業務模塊管。這是一個依賴注入的過程,依賴注入實現起來非常簡單,不需要很重的框架去實現。

圖 6

如圖 6 所示的例子。module 包負責管理所有的業務模塊,通過 iplayer、IEquip 聲明具體的業務模塊需要提供什么樣的方法,然后再通過對應的全局變量,去存放這兩個口的具體實現,這是很簡單的依賴注入的方式。譬如,圖 6 中的 Player 模塊可以引入 module,然后把自己注入到 module 的 player 實現當中。譬如玩家注冊送裝備,就可以調用裝備模塊送裝備,而不會直接地調裝備模塊,會變成間接的。只要依賴 module,然后把自己注冊進去就可以。

裝備模塊也相同,啟動的時候把自己注冊進去,可能裝備升級的時候要扣錢,可能對應的調用玩家模塊,只需要調 module.player 即可,無需注意它是在哪里實現的。最關鍵的一點,這個 module 作為總的模塊管理的一個包,我們可以在一份文件里面很清楚的看到,業務對外提供哪些方法,哪些接口。平時,我在 review 代碼時,基本只看這一份。

實踐總結

接口在 Go 語言中是非常重要的,要重點掌握。接口的運用是很靈活的,腦筋要會急轉彎。解耦并不需要很厚重的封裝。可以惡心自己,但不要惡心別人。

去 DSL 的嘗試

我們在通信協議上有一套自己的 DSL,但在實際應用中存在一個問題,即它的功能隱藏在語法中,甚至有一些功能隱藏在工具參數背后,同樣的文檔通過不同的命令行參數生成的長度也不同,因此,這里有一個學習成本。

開發人員在設計 DSL 時,腦海中需要聯想原生的語言最終生成出來會是什么,比如客戶端對應生成什么、服務端對應生成什么。其實,大腦有一定的工作負擔。當大家在寫開源項目,譬如 markdown 文件時,如果沒有可視化工具輔助,你要在腦海里面聯想,寫出來的東西最后別人看到是什么樣的,而所有的 DSL 都會有這樣一個問題。

另外,開發的過程中,我需要反復地在工具間切來切去,可能需要改一下 DSL 的描述,然后切到命令行生成代碼,再切回來看對應的生成產物,再繼續編寫代碼。大家在這一塊的工作其實并不流暢。而 Go 的代碼很清晰簡潔,沒有多余的符號,因此,一份代碼本身就是一份很好的文檔。 圖 7

如圖 7 所示,大家一看就知道每個字段的用處。那么,如何有效利用代碼本身呢?我想了一個辦法,即讓大家去寫 Go 的代碼,只要把 Go 的代碼寫好,針對這份代碼去生成對應的客戶端的代碼和序列化的東西,就不用在 DSL 上來回切換,這就是我們的一個 RPC 參數返回值,直接寫到代碼即可,不需要到 DSL 里面去切,寫出來的樣子即最后的樣子。我們對通信協議中用到的數據類型做了簡單的歸納,其中用到的類型很簡單。簡單類型:整形、浮點型,復合類型:自負串、數組、slice、map、指針、結構體。只要這幾個實現了,就可以進行組合,已經完全滿足平時使用。

基于AST的實現

Go 的 runtime 中提供了解析 Go 代碼所需的庫,一開始在小規模用的時候我們覺得很舒服,go/passer 一分析,就可以拿到里面的結構體字段、類型。go/doc 可以分析注釋中的特殊符號,比如通過注釋的約定,去約定要不要生成結構體對應的代碼。Go 的 template 包做代碼生成,把代碼生成邏輯和代碼分析邏輯做解耦。Go generate 用于代碼生成,原理比較簡單,它負責把代碼讀進來,你的工具就可以取到代碼做分析,把它轉成新的產物。但是用 AST 的一個問題是,往后繼續加工會發現,包引用關系不好分析。單份文件讀的時候很方便,但是分析整個項目時,包引用關系的分析比較難。另外,類型轉義不太好分析,持續增加功能的時候代碼變得異常復雜。types 包也許可以幫忙,它起到一定的簡化作用,但是畢竟我們項目做的比較匆忙。因此,這個東西就沒有花太多時間繼續深入。

基于反射的實現

后來,因為需要繼續往上疊功能,所以我們改成用基于反射去實現,這樣相對簡單,因為類型信息提供得很詳盡,代價是要注冊類型,并且需要編譯兩次代碼,這是反射的代價。反射雖然讓工具變得更簡單,但是需要付出這樣的成本。關閉編譯優化可以緩解一下。

優化 RPC

另外,我們實現了反序列化格式后,順便又優化了 RPC。Go 原生的 RPC 序列化有一些限制性。Gob 支持 BinaryMarshaler 和 BinaryUnmarshaler 接口。生成對應方法,類型的序列化和反序列化就被接管了?;谠?RPC 包,稍微封裝一下就得到了符合項目需要的 RPC。一個 RPC 接口在一個代碼中就可以看得一清二楚,不用再到別的地方看,這是我們目前做起來最舒服的一點。

實踐總結

適合服務端只用 Go 以及客戶端語言單一的項目。但是這個東西是有限制的,這就是格局問題。當你在做一個東西的時候,你的定位需要考慮很多人的需求,可能相應地在要在開發效益和使用體驗、調用效率上做一些犧牲,來換取一些通用性。我們這種做法,由于項目的周期是比較短,不會與很多客戶端配合做很長時間,所以適合服務端只用 Go 以及客戶端語言單一的項目。但是如果要做多語言的協作,還是建議用行業標準的做法。多語言協作的項目推薦 PRotobuf、JSON。

另外可視化也是一種選擇。 DSL 的優化不只是把 DSL 干掉這一條路,譬如 markdown 雖然書寫時,最終產物不直觀,但是可以通過工具輔助達到比較好的編輯體驗。

最后,基于我剛才所分享的內容,我想講一些自己的感想。在做項目時,不同的公司愿景不一樣,人員組成不一樣,它所產生的架構差異會非常大。像劉奇老師的做法,它選擇去和更多人配合,部署一個更大的格局,就需要去選擇一些行業通用的標準,盡量避免去做一些特殊化的東西。

反過來,一個愿景很小、時間很短的項目,并且沒有外部合作的預期,它產生出來的東西就是大量的專屬化定制。因為人員問題、資金問題、周期要求問題,產生出來的東西開發效率會不一樣。

在今年 1 月由七牛云主辦的 ECUG Con 十周年盛會上,真有趣技術總監陳明達帶來了題為《 Go 在游戲行業中的工程實踐》的精彩分享,深入講解了 Go 的工程經驗,錯誤和異常處理,interface 的應用以及去 DSL 的嘗試等內容。

陳明達

真有趣技術總監。從事游戲行業,開發過《神仙道》《仙俠道》等項目。


ECUG 全稱為 Effective Cloud User Group(實效云計算用戶組),由七牛云 CEO 許式偉發起,集結了一批具有高端視角并仍醉心于技術本身的同仁,共同關注云計算前沿技術的最新成果和分布式開發、運維的最佳實踐。

點擊「閱讀原文」,了解 ECUG。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产女精品视频网站免费| 国产精品网站大全| 亚洲国产精品成人精品| 成人黄色免费在线观看| 久久精品91久久久久久再现| 日韩av免费网站| 伊人久久久久久久久久久久久| 午夜免费久久久久| 国产精品久久久久久搜索| 日韩中文字幕网| 欧美精品一区二区三区国产精品| 黑人巨大精品欧美一区二区| 91亚洲精品在线| 91精品中文在线| 中文字幕日本精品| 亚洲精品欧美日韩| 91精品国产成人| 日本a级片电影一区二区| 91高潮在线观看| 伊人久久男人天堂| 亚洲成人网av| 成人免费视频xnxx.com| 亚洲在线第一页| 久久夜精品香蕉| 久久久视频免费观看| 欧美xxxx综合视频| 国产精品福利无圣光在线一区| 亚洲成人av中文字幕| 亚洲欧洲一区二区三区久久| 日韩网站免费观看| 国内精品400部情侣激情| 欧美巨乳在线观看| 欧美精品久久久久久久免费观看| 在线免费观看羞羞视频一区二区| 在线日韩日本国产亚洲| 欧美激情视频一区二区| 亚洲一区二区三区在线视频| 国产精品视频中文字幕91| 粗暴蹂躏中文一区二区三区| 国产女同一区二区| 欧美成人免费全部观看天天性色| 国产三级精品网站| 97色伦亚洲国产| 国内精品在线一区| 久久av红桃一区二区小说| 久久99精品久久久久久琪琪| 成人美女免费网站视频| 在线观看不卡av| 色偷偷偷综合中文字幕;dd| 亚洲精品福利免费在线观看| 久久免费视频观看| 欧美激情视频一区| 九九热最新视频//这里只有精品| 国产在线精品自拍| 日本精品在线视频| 在线电影中文日韩| 亚洲国产精品va在线| 8x海外华人永久免费日韩内陆视频| 国产成人久久久精品一区| 久久久亚洲精品视频| 91色p视频在线| 国产精品成人免费电影| 国产精品伦子伦免费视频| 欧美激情免费观看| 日韩激情片免费| 国外成人在线播放| 2019中文字幕在线| 国产免费一区二区三区在线观看| 国内精品久久久久伊人av| 亚洲精品中文字幕有码专区| 久久激情五月丁香伊人| 91精品视频专区| 久久精品2019中文字幕| 视频在线观看一区二区| 国产精品毛片a∨一区二区三区|国| 亚洲激情中文字幕| 亚洲男人天堂古典| 久久精品福利视频| 欧美成人免费va影院高清| 日日噜噜噜夜夜爽亚洲精品| 91免费的视频在线播放| 国产成人一区三区| 欧美一级大片在线免费观看| 亚洲最大av网| 亚洲最大在线视频| 国产欧美亚洲视频| 国产精品视频色| 亚洲人成电影在线播放| 精品视频偷偷看在线观看| 日韩av资源在线播放| 精品亚洲永久免费精品| 日韩专区在线播放| 777午夜精品福利在线观看| 精品国产31久久久久久| 美日韩精品视频免费看| 久久久精品网站| 国产精品爽爽爽爽爽爽在线观看| 国产精品美女www| 久久久久久九九九| 欧美性猛交xxxx乱大交蜜桃| xxx欧美精品| 国产91免费看片| 亚洲精品久久久一区二区三区| 欧美性色视频在线| 色妞色视频一区二区三区四区| 亚洲欧美日韩国产中文专区| 国产成人aa精品一区在线播放| 欧美一级片免费在线| 色无极影院亚洲| 91国在线精品国内播放| 57pao国产精品一区| 一本色道久久88综合亚洲精品ⅰ| 97国产精品视频人人做人人爱| 欧美在线精品免播放器视频| 57pao成人永久免费视频| 91免费视频网站| 国产91精品久久久久| 日韩av在线一区| 日韩电影大全免费观看2023年上| 97久久精品人人澡人人爽缅北| 97视频在线观看免费高清完整版在线观看| 黄网站色欧美视频| 国产精品91在线观看| 欧美性猛交xxxx黑人| 色多多国产成人永久免费网站| 久久天堂av综合合色| 日韩va亚洲va欧洲va国产| 日韩**中文字幕毛片| 韩国三级电影久久久久久| 国产一区二区在线免费| 亚洲欧美在线一区| 久久视频在线播放| www.国产一区| 色妞一区二区三区| 午夜美女久久久久爽久久| 日韩免费观看网站| 久久精品小视频| 狠狠做深爱婷婷久久综合一区| 午夜精品美女自拍福到在线| 日韩精品视频免费专区在线播放| 国内精品中文字幕| 日韩最新中文字幕电影免费看| 日韩欧美福利视频| 亚洲国产成人在线播放| 国内精品久久久久影院优| 午夜精品久久久久久久99热| 欧美大胆在线视频| 欧美视频第一页| 亚洲第一精品夜夜躁人人爽| 一区二区国产精品视频| 亚洲国产毛片完整版| …久久精品99久久香蕉国产| 亚洲剧情一区二区| 国产成人综合亚洲| 精品国产户外野外| 日韩av在线免费观看| 欧美专区在线播放| 国产免费一区二区三区香蕉精| 久久久精品免费| 亚洲人成电影在线观看天堂色| 久久99精品久久久久久青青91| 日本精品视频在线播放| 国内精品久久久久久| 欧美激情视频网址|