成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

別背八股文了,WebSocket 是什么,我勸你花幾分鐘讓面試官驚艷!

開發(fā) 前端
WebSocket 前端的使用非常簡(jiǎn)單,我自然會(huì)聯(lián)想到:如果我做全棧開發(fā),用 Nodejs 實(shí)現(xiàn) WebSocket 服務(wù)端,有原生的模塊可以支持嗎?

前言

作為前端工程師,我們幾乎每天都在使用 ajax / fetch 請(qǐng)求與后端進(jìn)行數(shù)據(jù)交互,這種基于請(qǐng)求-響應(yīng)的通訊模式,我們?cè)偈炀毑贿^了,無論是C端產(chǎn)品或者是B端產(chǎn)品,都離不開這種通訊模式。但是像即時(shí)通訊IM類場(chǎng)景,通常不會(huì)選擇這種“你來我回”的通信模式,而是會(huì)選擇 WebSocket 這類的全雙工通信模式。

本文會(huì)帶您全方位去了解一下 WebSocket 的本質(zhì),方便您搞清楚“Connection: Upgrade 是什么意思,為什么是它?”、“Upgrade: WebSocket 又是什么意思?這就可以雙向通信了?”、“WebSocket 和 HTTP/TCP 到底有什么關(guān)聯(lián)?八股文背了還是不理解”之類的問題,幫助您無論面試或工作時(shí)被問到 WebSocket 都能有更多細(xì)節(jié)可以聊,妥妥的一個(gè)加分項(xiàng)!

最后通過一個(gè)在線聊天室實(shí)戰(zhàn)案例帶大家熟悉下 WebSocket 的全棧使用,可點(diǎn)擊在線聊天室[3]進(jìn)行體驗(yàn)。

圖片圖片

認(rèn)識(shí) WebSocket

WebSocket 是一種網(wǎng)絡(luò)通信協(xié)議,它建立在 HTTP 之上,提供了在單個(gè) TCP 連接上進(jìn)行全雙工通信的能力。這意味著服務(wù)器和客戶端可以互相發(fā)送和接收消息,而不需要每次都重新建立連接。WebSocket 最初由 HTML5 規(guī)范定義,具體可以參考WebSockets Living Standard[4]。而現(xiàn)在,WebSocket 已被廣泛支持并應(yīng)用于各種應(yīng)用,包括實(shí)時(shí)聊天、多人在線游戲、股票交易系統(tǒng)等需要實(shí)時(shí)數(shù)據(jù)更新的場(chǎng)景。

WebSocket 的兼容性如何?

作為前端開發(fā),對(duì) API 的兼容性還是非常敏感的,我們先來看看 WebSocket 的兼容性怎么樣。

圖片圖片

可以看到,主流瀏覽器都支持了 WebSocket,IE10 及以上版本也對(duì) WebSocket 提供了完備的支持,所以我們可以大膽地使用起來!

WebSocket 的前端用法

瀏覽器 JS 運(yùn)行時(shí)提供了 WebSocket[5] 這個(gè) API,可以用來創(chuàng)建和管理 WebSocket 連接。

使用也非常簡(jiǎn)單,構(gòu)造實(shí)例后只有幾個(gè)簡(jiǎn)單的方法調(diào)用,一看就會(huì)。

// 創(chuàng)建一個(gè)新的 WebSocket 連接
const socket = new WebSocket('ws://your-websocket-server-url')

// 監(jiān)聽連接打開
socket.onopen = (e) => {
  console.log('WebSocket is connected.')
  // 連接打開后,你可以發(fā)送消息
  socket.send('Hello Server!')
}

// 監(jiān)聽消息
socket.onmessage = (e) => { console.log('Message from server: ', e.data) }

// 監(jiān)聽關(guān)閉
socket.onclose = (e) => { console.log('Connection closed.') }

// 監(jiān)聽錯(cuò)誤
socket.onerror = (err) => { console.error('WebSocket Error: ', err) }

// 如果你想主動(dòng)關(guān)閉連接,可以調(diào)用 close 方法
// socket.close()

wss:// 是 ws:// 的 TLS 加持版,可以類比于 https:// 和 http://

Nodejs 原生支持 WebSocket 嗎?

WebSocket 前端的使用非常簡(jiǎn)單,我自然會(huì)聯(lián)想到:如果我做全棧開發(fā),用 Nodejs 實(shí)現(xiàn) WebSocket 服務(wù)端,有原生的模塊可以支持嗎?

經(jīng)過查詢了解到,Node 原生模塊中并未直接支持 WebSocket 服務(wù)端的開箱使用,一個(gè)比較流行的庫(kù)是 ws[6]。

那么 ws 這個(gè)庫(kù)是怎么實(shí)現(xiàn) WebSocket 服務(wù)端的呢?怎么才能和瀏覽器的 WebSocket 實(shí)現(xiàn)對(duì)接上?

直接讀源碼肯定是看不懂的,即便看懂了一些過程調(diào)用,也是懵逼的,我們往下看。

WebSocket 協(xié)議概覽

我們知道,通訊是基于協(xié)議的,WebSocket 也有它的專屬協(xié)議。ws 的實(shí)現(xiàn)它也是要遵循這個(gè)協(xié)議,才能和客戶端實(shí)現(xiàn)匹配上,完成通訊。

這個(gè)協(xié)議我們?nèi)ツ睦锟茨??根?jù) wikipedia 的介紹,我們知道,WebSocket 的標(biāo)準(zhǔn)化是基于IETF 的 RFC 6455 WebSocket Protocol[7]。大致瀏覽后,我圈出了協(xié)議里一些值得關(guān)注的內(nèi)容。閱讀這類協(xié)議時(shí),我們可以先挑重點(diǎn)看,對(duì)協(xié)議有一個(gè)基本的認(rèn)識(shí)即可。

圖片圖片

圖片圖片

我們了解到一些關(guān)鍵詞:

  1. 連接握手
  2. 怎么建立連接
  3. 數(shù)據(jù)發(fā)送和接收,數(shù)據(jù)幀
  4. 關(guān)閉握手
  5. 插件,相關(guān) HTTP 頭部字段

雖然有了一些關(guān)鍵詞在腦海中,但我們對(duì)整個(gè)通訊過程肯定還有一連串疑問。帶著疑問,我們繼續(xù)往下看協(xié)議的具體內(nèi)容。

  1. 我們會(huì)了解到 WebSocket 出現(xiàn)的背景,它是為了解決什么,很顯然,普通的 HTTP 請(qǐng)求不適合一些雙向通信場(chǎng)景,比如聊天、股票、游戲等。
  2. 即便普通 HTTP 請(qǐng)求能通過一些業(yè)務(wù)設(shè)計(jì)滿足雙向通信需求,性能問題也很大,TCP 連接的開銷等問題都要考慮在內(nèi)。
  3. WebSocket 就是希望在一個(gè) TCP 連接上,開辟雙工通道,實(shí)現(xiàn)全雙工實(shí)時(shí)通信。
  4. 之所以選擇在 HTTP 協(xié)議的基礎(chǔ)上去實(shí)現(xiàn) WebSocket,也是一種權(quán)衡和取舍,可能會(huì)犧牲一些性能,但是也極大地復(fù)用了已有的網(wǎng)絡(luò)基礎(chǔ)設(shè)施,包括協(xié)議、安全、代理、認(rèn)證等。

圖片圖片

WebSocket 協(xié)議 - 連接握手

再往下翻一翻協(xié)議,我們能翻到最關(guān)鍵的部分,這也是面試?yán)锬芎兔嬖嚬俅档膬?nèi)容,請(qǐng)仔細(xì)看!

很多人面試被問到 WebSocket,就說 WebSocket 可以雙向通信,這是和 HTTP 最大的不同。講道理,這種回復(fù)面試官已經(jīng)聽膩了。

如果你能告訴面試官,WebSocket 的協(xié)議涉及到以下幾個(gè) HTTP 頭部字段,并簡(jiǎn)述一下各個(gè)字段的簡(jiǎn)單含義,我相信你的面試絕對(duì)加分!

圖片圖片

我們先看請(qǐng)求頭:

  • WebSocket 請(qǐng)求一定是 GET 類型的。
  • Origin: 瀏覽器客戶端會(huì)帶上,包含 Origin 是為了安全考慮,充分利用瀏覽器的同源策略。
  • Connection: Upgrade 和 Upgrade: websocket。這是客戶端告知服務(wù)端需要升級(jí)協(xié)議,并且升級(jí)的協(xié)議為 websocket。
  • Sec-WebSocket-Key:由客戶端(比如瀏覽器)隨機(jī)生成,16位隨機(jī)數(shù)經(jīng)過 base64 編碼后得到。響應(yīng)頭 Sec-WebSocket-Accept 是與它搭配使用的,用來確保請(qǐng)求的有效性和安全性。
  • Sec-WebSocket-Protocol:不是必選的。用來約定應(yīng)用層面的子協(xié)議,使得客戶端和服務(wù)器能夠靈活地協(xié)商并選擇一個(gè)雙方都能理解的協(xié)議來進(jìn)行通信。如果服務(wù)端選擇使用某個(gè)子協(xié)議通信,則會(huì)在響應(yīng)頭中返回。

再看響應(yīng)頭:

  • 服務(wù)端返回 101 Switching Protocols,代表握手成功,協(xié)議切換到 WebSocket。
  • Connection: Upgrade 和 Upgrade: websocket,用于告知客戶端可以升級(jí)為 websocket 協(xié)議。
  • Sec-WebSocket-Accept:基于 Sec-WebSocket-Key 處理得到,處理公式如下,其中"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"是一個(gè)固定的字符串:
base64-encode(sha1(Sec-WebSocket-Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))

引用 wikipedia 的一張圖,可以看得更清楚!

圖片圖片

WebSocket 協(xié)議 - 數(shù)據(jù)幀

建立了連接握手后,WebSocket 就可以發(fā)送和接受消息數(shù)據(jù)了,消息是由一個(gè)或多個(gè)幀組成的。我們先看看這兩張圖了解一下數(shù)據(jù)幀的結(jié)構(gòu)。

圖片圖片

圖片圖片

其中 Opcode 是操作碼,具體見下表。

圖片圖片

由于存在數(shù)據(jù)比較大的可能,這時(shí)需要切片傳輸,WebSocket 消息數(shù)據(jù)支持分片傳輸。

  • 當(dāng) FIN = 1 且 OpCode ≠ 0 時(shí),代表這一幀數(shù)據(jù)不是分片處理的。
  • 當(dāng) FIN = 0 時(shí),如果 OpCode = 0,代表這一幀數(shù)據(jù)是某個(gè)分片的中間數(shù)據(jù)幀;如果 OpCode ≠ 0,代表這一幀數(shù)據(jù)是一個(gè)分片數(shù)據(jù)中的起始幀。

WebSocket 能發(fā)送文本數(shù)據(jù)或二進(jìn)制數(shù)據(jù),這個(gè)是體現(xiàn)在 OpCode 上。如果起始幀的 OpCode 是 1,則代表是文本數(shù)據(jù);如果起始幀的 OpCode 是 2,則代表是二進(jìn)制數(shù)據(jù)。

WebSocket 協(xié)議 - 關(guān)閉連接

我們看看規(guī)范中,關(guān)閉握手這部分是怎么說的。

圖片圖片

WebSocket 任何一端都可以發(fā)起關(guān)閉連接。

當(dāng)一方準(zhǔn)備關(guān)閉連接時(shí),應(yīng)該發(fā)送 Close Frame 開始關(guān)閉握手,之后不應(yīng)該再發(fā)送任何數(shù)據(jù);

另一方收到 Close Frame 時(shí),需要回復(fù) Close Frame,并且準(zhǔn)備釋放資源,同時(shí)也應(yīng)該丟棄后續(xù)從這個(gè)連接上可能接收到的數(shù)據(jù)。

發(fā)起方收到 Close Frame 控制幀后,關(guān)閉連接釋放資源,不再接收數(shù)據(jù)。

這種 WebSocket 關(guān)閉握手機(jī)制也是在 TCP 握手機(jī)制上的一種補(bǔ)充,更好地保證端到端通信的可靠性!

有的朋友可能會(huì)考慮到這個(gè)問題:當(dāng)客戶端發(fā)送 Close Frame 后,服務(wù)端正常接收到,并且回復(fù) Close Frame,但是由于網(wǎng)絡(luò)問題客戶端沒有服務(wù)端響應(yīng)的 Close Frame,這種情況是怎么關(guān)閉 WebSocket 連接的?

實(shí)際上,TCP 連接也有它的超時(shí)和重試機(jī)制,當(dāng)一段時(shí)間內(nèi)沒有數(shù)據(jù)傳輸時(shí),也會(huì)斷開連接。所以我們無需擔(dān)心這一點(diǎn)。

當(dāng)這種沒有成功關(guān)閉握手但是關(guān)閉了 TCP 連接的情況發(fā)生時(shí),onclose事件回調(diào)中收到的錯(cuò)誤碼應(yīng)該是 1006,這一點(diǎn)可以在上面的表格中找到。

正常關(guān)閉是 1000。

在實(shí)際業(yè)務(wù)實(shí)現(xiàn)上,還會(huì)通過 ping-pong 之類的心跳檢測(cè)機(jī)制來保證可靠性。

回顧 ws 關(guān)鍵源碼

有了這些知識(shí)儲(chǔ)備后,再來看 ws 的實(shí)現(xiàn)源碼,可能就會(huì)有頭緒一點(diǎn)。

當(dāng)你看到這部分,你會(huì)知道它在校驗(yàn)頭部字段是否符合協(xié)議要求,準(zhǔn)備升級(jí)協(xié)議...

圖片圖片

當(dāng)你看到這個(gè) 101 狀態(tài)碼,你會(huì)恍然大悟:“哦,原來是在這里完成了協(xié)議的升級(jí)!”雖然還有些細(xì)節(jié)看不懂,但是無傷大雅!

圖片圖片

當(dāng)你看到這里時(shí),你會(huì)知道,如果客戶端嘗試通過普通的 HTTP 請(qǐng)求來連接 WebSocket 服務(wù),服務(wù)端應(yīng)該返回 426 Upgrade Required 告訴客戶端,“你該升級(jí)協(xié)議再跟我對(duì)話!”

圖片圖片

本文不是源碼解讀,點(diǎn)到為止,我們往下看。

為什么選擇 Socket.IO

實(shí)際將 WebSocket 運(yùn)用到生產(chǎn)環(huán)境時(shí),我們一般不會(huì)直接使用 ws 這種協(xié)議實(shí)現(xiàn)庫(kù),而是會(huì)選擇在應(yīng)用層面進(jìn)行了一些封裝的庫(kù),比如 Socket.IO[8]。

圖片圖片

這是因?yàn)樵?WebSocket 實(shí)際使用過程中,還有很多問題要考慮,比如心跳檢測(cè)、優(yōu)雅降級(jí)、房間隔離、命名空間隔離、API 的易用性等。而這些,Socket.IO 已經(jīng)開箱支持。

準(zhǔn)確說,Socket.IO 并非是一個(gè) WebSocket 實(shí)現(xiàn),而是一個(gè)事件驅(qū)動(dòng)的低延遲雙向通訊方案。

它的底層通訊不一定是基于 WebSocket 的,可能會(huì)根據(jù)情況選擇 HTTP 長(zhǎng)輪詢、WebTransport[9]。

WebTransport 是一個(gè)基于 HTTP/3 的通訊技術(shù),可實(shí)現(xiàn)可靠通信和不可靠通信。HTTP/3 底層基于 Google 的 QUIC 協(xié)議,而 QUIC 協(xié)議是基于 UDP 的。

圖片圖片

Socket.IO 有它的約定和規(guī)則,或者叫協(xié)議,只要遵循這個(gè)協(xié)議,就能完成客戶端和服務(wù)端的實(shí)現(xiàn),所以你會(huì)看到,它也有多語言的實(shí)現(xiàn),甚至在客戶端還有小程序的實(shí)現(xiàn)。

圖片圖片

這個(gè)協(xié)議其實(shí)也就對(duì)應(yīng)著Socket.IO 的底層引擎 Engine.IO[10]。

圖片圖片

雖然現(xiàn)在大部分瀏覽器都支持了 WebSocket,但是也不排除某些遠(yuǎn)古項(xiàng)目的存在,它必須運(yùn)行在“古董”瀏覽器版本之上。Socket.IO 考慮到了這一點(diǎn),它的自動(dòng)優(yōu)雅降級(jí)完美解決了這一問題。

圖片圖片

Socket.IO 的心跳檢測(cè)機(jī)制和自動(dòng)重連也是實(shí)際業(yè)務(wù)中必不可少的!

更多的特性還有:

  • 對(duì)話回調(diào)
  • 廣播
  • 房間
  • 命名空間多路復(fù)用
  • ...

Socket.IO 的通訊過程

當(dāng)我們打開一個(gè) Socket.IO 的客戶端頁面時(shí),會(huì)發(fā)現(xiàn) Network 里發(fā)出了多個(gè)請(qǐng)求,在 101 websocket 連接建立之前,有 4 個(gè) xhr 請(qǐng)求,其中還有一個(gè)是 POST 請(qǐng)求。

圖片圖片

Socket.IO 在升級(jí)機(jī)制中解釋了這一點(diǎn),直接建立可靠可用的 WebSocket 連接并非一件很輕松的事情,通常從 HTTP 開始平滑升級(jí)到 WebSocket,對(duì)連接的可靠性和用戶體驗(yàn)來說是更好的。

升級(jí)協(xié)議會(huì)經(jīng)歷這么一些步驟,對(duì)應(yīng)著我們?cè)谏厦婵吹降膸讉€(gè) Network 請(qǐng)求。

圖片圖片

我這個(gè)項(xiàng)目開始得很早,所以EIO=3,代表協(xié)議版本號(hào)是3,目前 Engine.IO 已經(jīng)升級(jí)到版本4了。

在 Socket.IO 的 HTTP 長(zhǎng)輪詢模式中,使用長(zhǎng)時(shí)間運(yùn)行的 GET 請(qǐng)求接收數(shù)據(jù),使用短期運(yùn)行的 POST 請(qǐng)求發(fā)送數(shù)據(jù)。

了解了這些機(jī)制,并且查看 API 用法后,就可以開始運(yùn)用了,一些高級(jí)用法可以在使用過程中再去探索!

聊天室的全棧實(shí)現(xiàn)

基于以上理解,我們開始搭建博客項(xiàng)目中的聊天室功能,我們會(huì)實(shí)現(xiàn)這些主要能力:

  • 成功創(chuàng)建 Socket.IO 連接
  • 展示聊天室的系統(tǒng)通知信息(涉及到單播和廣播)
  • 聊天對(duì)話功能(廣播)

我們首先把依賴安裝好,客戶端使用socket.io-client[11],服務(wù)端使用socket.io[12]即可。

服務(wù)端開啟 WebSocket 服務(wù)

第一步是把 WebSocket 服務(wù)啟動(dòng)。由于本項(xiàng)目開始較早,socket.io 版本是 2.5,大家對(duì)照文檔的時(shí)候按 2.x 文檔看就好。

圖片圖片

socket.io 可以利用已經(jīng)存在的 HTTP 服務(wù),由于項(xiàng)目是用 Express 搭建的,我們直接與 Express 共享一個(gè) HTTP 服務(wù)即可。

io 實(shí)例化后,監(jiān)聽到 connection 事件就代表有客戶端過來了,可以開始干活了。我這里是把聊天室相關(guān)的邏輯都放在了 chatroom 這個(gè)命名空間下。

圖片圖片

of 的作用就是初始化并使用命名空間。

客戶端服務(wù)端建立連接

第二步是建立連接。首先引入依賴。

import io from "socket.io-client";

再進(jìn)行實(shí)例化,得到一個(gè) socket 實(shí)例。

this.socket = io(process.env.VUE_APP_SOCKET_SERVER + "/chatroom");

有了這個(gè) socket,我們就能監(jiān)聽各種事件了。

圖片圖片

聊天室的系統(tǒng)通知信息

當(dāng)一個(gè)客戶端連接上服務(wù)器時(shí),服務(wù)器會(huì)發(fā)送一條消息,“hello,歡迎您加入在線聊天室!”這是通過單播實(shí)現(xiàn)的,只要拿著socket對(duì)象,調(diào)用其emit方法就行。

圖片圖片

除了對(duì)這個(gè)客戶端打招呼外,還需要告訴其他用戶,有新人加入了。這是通過socket.broadcast廣播實(shí)現(xiàn)的。

socket.broadcast.emit('broadcast', param);

當(dāng)有人退出聊天室,會(huì)觸發(fā) disconnect 事件,此時(shí)我們可以廣播通知其他人。

圖片圖片

這就是我們?cè)谇岸隧撁婵吹降男Ч?/p>

圖片圖片

聊天對(duì)話功能

由于我們做的是聊天室,相當(dāng)于一個(gè)群聊,就不涉及到單播聊天了,直接用廣播就行。

用戶在客戶端發(fā)聊天消息時(shí),是用到socket對(duì)象的emit進(jìn)行發(fā)送。

圖片圖片

這個(gè)chat事件是在客戶端連接上服務(wù)端時(shí)開始監(jiān)聽的,在這個(gè)回調(diào)里,我們需要把內(nèi)容廣播給除發(fā)送者之外的其他用戶,子事件名是new_chat_content。

圖片圖片

而其他用戶則會(huì)通過客戶端監(jiān)聽廣播事件中的new_chat_content子事件拿到聊天數(shù)據(jù),最終呈現(xiàn)到界面上。

圖片圖片

圖片圖片

以上都是通訊上的設(shè)計(jì),了解了這個(gè)機(jī)制,UI 的展示就非常簡(jiǎn)單了,畢竟 UI = Render(data),不做更多介紹!

小結(jié)

本文中,我首先分享了我對(duì) WebSocket 協(xié)議的一些理解,希望對(duì)還不太理解這塊的朋友起到一點(diǎn)幫助作用。面試?yán)?,WebSocket 是一個(gè)常問的考點(diǎn),如果你回答的僅僅是“全雙工通信”,可能并不能起到一個(gè)很好的效果,把文中小知識(shí)甩面試官臉上吧,哈哈哈!

最終通過一個(gè)實(shí)際案例,帶大家理解一個(gè)聊天室功能的設(shè)計(jì)思路,在實(shí)際落地的過程中夯實(shí)對(duì) WebSocket 協(xié)議的理解。

責(zé)任編輯:武曉燕 來源: 程序員白彬
相關(guān)推薦

2021-10-26 14:40:03

MySQL SQL 語句數(shù)據(jù)庫(kù)

2021-11-04 14:32:17

Spring 面試作用域

2021-10-21 14:43:23

Java 語言 Java 基礎(chǔ)

2021-07-26 14:59:23

面試Redis內(nèi)存數(shù)據(jù)庫(kù)

2021-09-07 14:46:42

面試網(wǎng)絡(luò)HTTP 協(xié)議

2021-11-24 07:56:56

For i++ ++i

2024-02-23 19:17:12

構(gòu)造函數(shù)C++開發(fā)

2023-01-13 18:04:03

面試題消息中間件

2023-11-28 18:09:49

Java多態(tài)

2022-09-03 11:36:11

Python文件網(wǎng)絡(luò)

2021-10-26 17:05:55

Redis字符串復(fù)雜度

2025-05-07 01:20:11

SpringMVC核心機(jī)制

2021-08-01 22:59:43

Object八股文quals

2021-05-06 07:27:57

面試任務(wù)調(diào)度器

2023-09-22 08:27:39

2021-08-13 07:23:15

架構(gòu)秒殺系統(tǒng)

2021-04-14 10:02:59

網(wǎng)絡(luò)八股文協(xié)議

2023-11-29 17:28:07

2021-05-20 11:43:57

操作系統(tǒng)硬件軟件

2021-08-12 09:28:24

Java多線程變量
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 黄a大片| 欧亚av在线 | 成人毛片视频免费 | 国产色片在线 | 日日天天| 免费看av大片 | 久久久久久国产精品久久 | 欧美日韩综合视频 | 成人网在线看 | 91精品一区| 91av在线免费观看 | 欧美激情国产日韩精品一区18 | 网黄在线 | 久草.com| 狠狠的干 | 91av小视频 | 天天操天天射综合 | 国产亚洲一区二区三区在线 | 国产91丝袜在线播放 | 日本午夜视频 | 国产高清精品一区二区三区 | 日韩网站在线观看 | 97国产一区二区精品久久呦 | 久久99精品久久久久久琪琪 | 日韩一区二区三区精品 | 91天堂网 | 91精品综合久久久久久五月天 | 红色av社区 | 6080亚洲精品一区二区 | 九色综合网 | 一区二区三区亚洲 | 四虎影院在线播放 | av男人的天堂av | 美女视频一区二区三区 | 国产视频精品免费 | 成人不卡 | 国产乱码精品1区2区3区 | 国产精品久久久亚洲 | 亚洲欧美在线视频 | 亚洲精品久久久久久一区二区 | 涩色视频在线观看 |