日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【WebSocket初探】

發布時間:2025/3/8 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【WebSocket初探】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?????? 眾所周知,socket是編寫網絡通信應用的基本技術,網絡數據交換大多直接或間接通過socket進行。對于直接使用socket的client與服務端,一旦連接被建立則均可主動向對方傳送數據,而對于使用更上層的HTTP/HTTPS協議的應用,因為它們是非連接協議,所以通常僅僅能由client主動向服務端發送請求才干獲得服務端的響應并取得相關的數據。而當前越來越多的應用希望可以及時獲取服務端提供的數據,甚至希望可以達到接近實時的數據交換(比如非常多站點提供的在線客戶系統)。為達到此目的,通常採用的技術主要有輪詢、長輪詢、流等,而伴隨著HTML5的出現,相對更優異的WebSocket方案也應運而生。

一、????????????非WebSocket方案簡單介紹

1.??????輪詢

?????? 輪詢是由client定時向服務端發起查詢數據的請求的一種實現方式。早期的輪詢是通過不斷自己主動刷新頁面而實現的(在那個基本是IE統治瀏覽器的時代,那不斷刷新頁面產生的噪聲就難以讓人忍受),后來隨著技術的發展,特別是Ajax技術的出現,實現了無刷新更新數據。但本質上這些方式均是client定時輪詢服務端,這樣的方式的最顯著的缺點是假設client數量龐大而且定時輪詢間隔較短服務端將承受響應這些client海量請求的巨大的壓力。

2.??????長輪詢

?????? 在數據更新不夠頻繁的情況下,使用輪詢方法獲取數據時client常常會得到沒有數據的響應,顯然這樣的輪詢是一個浪費網絡資源的無效的輪詢。長輪詢則是針對普通輪詢的這樣的缺陷的一種改進方案,其詳細實現方式是假設當前請求沒有數據能夠返回,則繼續保持當前請求的網絡連接狀態,直到服務端有數據能夠返回或者連接超時。長輪詢通過這樣的方式降低了client與服務端交互的次數,避免了一些無謂的網絡連接。可是假設數據變更較為頻繁,則長輪詢方式與普通輪詢在性能上并無顯著差異。同一時候,添加連接的等待時間,往往意味著并發性能的下降。

3.??????流

????? 所謂流是指client在頁面之下向服務端發起一個長連接請求,服務端收到這個請求后響應它并不斷更新連接狀態,以確保這個連接在client與服務端之間一直有效。服務端能夠通過這個連接將數據主動推送到client。顯然,這樣的方案實現起來相對照較麻煩,并且可能被防火墻阻斷。

二、????????????WebSocket簡單介紹

1.??????WebSocket協議簡單介紹

?????? WebSocket是為解決client與服務端實時通信而產生的技術。其本質是先通過HTTP/HTTPS協議進行握手后創建一個用于交換數據的TCP連接,此后服務端與client通過此TCP連接進行實時通信。

WebSocket規范當前還沒有正式版本號,草案變化也較為迅速。Tomcat7(本文中的例程來自7.0.42)當前支持RFC 6455(http://tools.ietf.org/html/rfc6455)定義的WebSocket,而RFC 6455眼下還未凍結,將來可能會修復一些Bug,甚至協議本身也可能會產生一些變化。

??????? RFC6455定義的WebSocket協議由握手和傳輸數據兩個部分組成。

????來自client的握手信息類似例如以下:

GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13


??????? 服務端的握手信息類似例如以下:

HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat


?

??????? 一旦client和服務端都發送了握手信息而且成功握手,則傳輸數據部分將開始。傳輸數據對client和服務端而言都是一個雙工通信通道,client和服務端來回傳遞的數據稱之為“消息”。

client通過WebSocket URI發起WebSocket連接,WebSocket URIs模式定義例如以下:

?

ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ] wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]


?

??????? ws是普通的WebSocket通信協議,而wss是安全的WebSocket通信協議(就像HTTPHTTPS之間的差異一樣)。在缺省情況下,ws的port是80wss的port是443

??????? 關于WebSocke協議規范的完整詳盡說明,請參考RFC 6455

2.??????Tomcat7提供的WebSocket包簡單介紹

??????? Tomcat7提供的與WebSocket相關的類均位于包org.apache.catalina.websocket之中(包org.apache.catalina.websocket的實現包括于文件catalina.jar之中),它包括有類Constants、MessageInbound、StreamInbound、WebSocketServlet、WsFrame、WsHttpServletRequestWrapper、WsInputStream、WsOutbound。這些類的關系如圖 1所看到的。

?

???????????????????????????????????????????????????????????????? 圖1

??????? 包org.apache.catalina.websocket中的這些類為WebSocket開發服務端提供了支持,這些類的主要功能簡述例如以下:

??????? Constants:包org.apache.catalina.websocket中用到的常數定義在這個類中,它僅僅包括靜態常數定義,無不論什么邏輯實現。

??????? MessageInbound:基于消息的WebSocket實現類(帶內消息),應用程序應當擴展這個類并實現其抽象方法onBinaryMessageonTextMessage

?????? StreamInbound:基于流的WebSocket實現類(帶內流),應用程序應當擴展這個類并實現其抽象方法onBinaryDataonTextData

?????? WebSocketServlet:提供遵循RFC6455WebSocket連接的Servlet基本實現。client使用WebSocket連接服務端時,須要將WebSocketServlet的子類作為連接入口。同一時候,該子類應當實現WebSocketServlet的抽象方法createWebSocketInbound,以便創建一個inbound實例(MessageInboundStreamInbound)

?????? WsFrame:代表完整的WebSocket框架。

?????? WsHttpServletRequestWrapper:包裝過的HttpServletRequest對象。

?????? WsInputStream:基于WebSocket框架底層的socket的輸入流。

?????? WsOutbound:提供發送消息到client的功能。它提供的全部向client的寫方法都是同步的,能夠防止多線程同一時候向client寫入數據。

三、????????????基于Tomcat7WebSocket例程

??????? 利用當前HTML5Tomcat7WebSocket提供的支持,基本僅僅須要編寫簡單的代碼對不同的事件做對應的邏輯處理就能夠實現利用WebSocket進行實時通信了。

??????? Tomcat7WebSocket提供了3個例程(echochatsnake),下面就當中的echochat分別做一簡要解析。

1.??????echo例程

??????? echo例程主要演示下面功能:client連接服務端、client向服務端發送消息、服務端收到client發送的消息后將其原樣返回給client、client收到消息后將其顯示在網頁之上。

?????? 在client頁面選擇streamsmessages作為“Connectusing”,然后點擊“Connect”button,能夠在右側窗體看到WebSocket連接打開的消息。隨后點擊“Echo message”button,client將向服務端發送一條消息,在右側窗體,能夠看到,消息發出的后的瞬間,client已經收到了服務端原樣返回的消息。

??????? client頁面及執行效果截圖如圖 2所看到的。

??????????????????????????????????????????????????????????????????????????????????????????????????? 圖2

?????? client實現上述功能的核心腳本例如以下,其關鍵點通過凝視的形式加以說明:

<script type="text/javascript">var ws = null;// 界面元素可用性控制function setConnected(connected) {document.getElementById('connect').disabled = connected;document.getElementById('disconnect').disabled = !connected;document.getElementById('echo').disabled = !connected;}function connect() {// 取得WebSocket連接入口(WebSocket URI)var target = document.getElementById('target').value;if (target == '') {alert('Please select server side connection implementation.');return;}// 創建WebSocketif ('WebSocket' in window) {ws = new WebSocket(target);} else if ('MozWebSocket' in window) {ws = new MozWebSocket(target);} else {alert('WebSocket is not supported by this browser.');return;}// 定義Open事件處理函數ws.onopen = function () {setConnected(true);log('Info: WebSocket connection opened.');};// 定義Message事件處理函數(收取服務端消息并處理)ws.onmessage = function (event) {log('Received: ' + event.data);};// 定義Close事件處理函數ws.onclose = function () {setConnected(false);log('Info: WebSocket connection closed.');};}// 關閉WebSocket連接function disconnect() {if (ws != null) {ws.close();ws = null;}setConnected(false);}function echo() {if (ws != null) {var message = document.getElementById('message').value;log('Sent: ' + message);// 向服務端發送消息ws.send(message);} else {alert('WebSocket connection not established, please connect.');}}// 生成WebSocket URI function updateTarget(target) {if (window.location.protocol == 'http:') {document.getElementById('target').value = 'ws://' + window.location.host + target;} else {document.getElementById('target').value = 'wss://' + window.location.host + target;}}// 在界面顯示log及消息function log(message) {var console = document.getElementById('console');var p = document.createElement('p');p.style.wordWrap = 'break-word';p.appendChild(document.createTextNode(message));console.appendChild(p);while (console.childNodes.length > 25) {console.removeChild(console.firstChild);}console.scrollTop = console.scrollHeight;}</script>


?????? 注:完整代碼參見apache-tomcat-7.0.42\webapps\examples\websocket\echo.html

?????? 以上client能夠依據“Connectusing”的不同選擇連接不同的服務端WebSocket。比如messages選項相應的服務端代碼例如以下,其核心邏輯是在收到client發來的消息后馬上將其發回client。

public class EchoMessage extends WebSocketServlet {private static final long serialVersionUID = 1L;private volatile int byteBufSize;private volatile int charBufSize;@Overridepublic void init() throws ServletException {super.init();byteBufSize = getInitParameterIntValue("byteBufferMaxSize", 2097152);charBufSize = getInitParameterIntValue("charBufferMaxSize", 2097152);}public int getInitParameterIntValue(String name, int defaultValue) {String val = this.getInitParameter(name);int result;if(null != val) {try {result = Integer.parseInt(val);}catch (Exception x) {result = defaultValue;}} else {result = defaultValue;}return result;}// 創建Inbound實例,WebSocketServlet子類必須實現的方法@Overrideprotected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request) {return new EchoMessageInbound(byteBufSize,charBufSize);}// MessageInbound子類,完畢收到WebSocket消息后的邏輯處理private static final class EchoMessageInbound extends MessageInbound {public EchoMessageInbound(int byteBufferMaxSize, int charBufferMaxSize) {super();setByteBufferMaxSize(byteBufferMaxSize);setCharBufferMaxSize(charBufferMaxSize);}// 二進制消息響應@Overrideprotected void onBinaryMessage(ByteBuffer message) throws IOException {getWsOutbound().writeBinaryMessage(message);}// 文本消息響應@Overrideprotected void onTextMessage(CharBuffer message) throws IOException {// 將收到的消息發回clientgetWsOutbound().writeTextMessage(message);}} }


??????? 注:完整代碼參見apache-tomcat-7.0.42\webapps\examples\WEB-INF\classes\websocket\echo\EchoMessage.java。

2.??????chat例程

??????? chat例程實現了通過網頁進行群聊的功能。每一個打開的聊天網頁都能夠收到全部在線者發出的消息,同一時候,每一個在線者也都能夠(也僅僅能夠)向其他全部人發送消息。也就是說,chat實例演示了怎樣通過WebSocket實現對全部在線client的廣播。

????????????????????????????????????????????????????????????????? 圖3

??????? chat例程client核心代碼例如以下,能夠看到事實上現方式與echo例程形式上稍有變化,本質依然是對WebSocket事件進行響應與處理。

<script type="text/javascript">var Chat = {};Chat.socket = null;Chat.connect = (function(host) {// 創建WebSocketif ('WebSocket' in window) {Chat.socket = new WebSocket(host);} else if ('MozWebSocket' in window) {Chat.socket = new MozWebSocket(host);} else {Console.log('Error: WebSocket is not supported by this browser.');return;}// 定義Open事件處理函數Chat.socket.onopen = function () {Console.log('Info: WebSocket connection opened.');document.getElementById('chat').onkeydown = function(event) {if (event.keyCode == 13) {Chat.sendMessage();}};};// 定義Close事件處理函數Chat.socket.onclose = function () {document.getElementById('chat').onkeydown = null;Console.log('Info: WebSocket closed.');};// 定義Message事件處理函數Chat.socket.onmessage = function (message) {Console.log(message.data);};});Chat.initialize = function() {if (window.location.protocol == 'http:') {Chat.connect('ws://' + window.location.host + '/examples/websocket/chat');} else {Chat.connect('wss://' + window.location.host + '/examples/websocket/chat');}};// 發送消息至服務端Chat.sendMessage = (function() {var message = document.getElementById('chat').value;if (message != '') {Chat.socket.send(message);document.getElementById('chat').value = '';}});var Console = {};Console.log = (function(message) {var console = document.getElementById('console');var p = document.createElement('p');p.style.wordWrap = 'break-word';p.innerHTML = message;console.appendChild(p);while (console.childNodes.length > 25) {console.removeChild(console.firstChild);}console.scrollTop = console.scrollHeight;});Chat.initialize();</script>
??????? 注:完整代碼參見apache-tomcat-7.0.42\webapps\examples\websocket\chat.html ? ??????? chat例程服務端代碼例如以下: public class ChatWebSocketServlet extends WebSocketServlet {private static final long serialVersionUID = 1L;private static final String GUEST_PREFIX = "Guest";private final AtomicInteger connectionIds = new AtomicInteger(0);private final Set<ChatMessageInbound> connections =new CopyOnWriteArraySet<ChatMessageInbound>();// 創建Inbound實例,WebSocketServlet子類必須實現的方法@Overrideprotected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request) {return new ChatMessageInbound(connectionIds.incrementAndGet());}// MessageInbound子類,完畢收到WebSocket消息后的邏輯處理private final class ChatMessageInbound extends MessageInbound {private final String nickname;private ChatMessageInbound(int id) {this.nickname = GUEST_PREFIX + id;}// Open事件@Overrideprotected void onOpen(WsOutbound outbound) {connections.add(this);String message = String.format("* %s %s",nickname, "has joined.");broadcast(message);}// Close事件@Overrideprotected void onClose(int status) {connections.remove(this);String message = String.format("* %s %s",nickname, "has disconnected.");broadcast(message);}// 二進制消息事件@Overrideprotected void onBinaryMessage(ByteBuffer message) throws IOException {throw new UnsupportedOperationException("Binary message not supported.");}// 文本消息事件@Overrideprotected void onTextMessage(CharBuffer message) throws IOException {// Never trust the clientString filteredMessage = String.format("%s: %s",nickname, HTMLFilter.filter(message.toString()));broadcast(filteredMessage);}// 向全部已連接的客戶端發送文本消息(廣播)private void broadcast(String message) {for (ChatMessageInbound connection : connections) {try {CharBuffer buffer = CharBuffer.wrap(message);connection.getWsOutbound().writeTextMessage(buffer);} catch (IOException ignore) {// Ignore}}}}
??????? 注:完整代碼參見apache-tomcat-7.0.42\webapps\examples\WEB-INF\classes\websocket\echo\ChatWebSocketServlet.java。

通過上述例程能夠看到WebSocket廣播實際上是通過遍歷全部連接并通過每一個連接向對應的client發送消息實現的。

四、????????????WebSocket實戰

??????? 實時向在線用戶推送通知是一個WebSocket應用的簡單場景,后臺提交通知信息以后,所在在線用戶均應非常快收到這個通知。通過上述例程了解WebSocket后,能夠嘗試編寫一個實現這個需求的WebSocket應用。

首先編寫一個用戶的Sample頁面,該頁面沒有實質的內容,可是在收到后臺發出的通知時要在右下角通過彈窗顯示通知的內容。其代碼例如以下: <!DOCTYPE html> <html> <head><title>Receive Message</title><style type="text/css">#winpop { width:200px; height:0px; position:absolute; right:0; bottom:0; border:1px solid #999999; margin:0; padding:1px; overflow:hidden; display:none; background:#FFFFFF}#winpop .con { width:100%; height:80px; line-height:80px; font-weight:bold; font-size:12px; color:#FF0000; text-align:center}</style><script type="text/javascript">// 彈窗相關function tips_pop(){var MsgPop=document.getElementById("winpop");var popH=parseInt(MsgPop.style.height);if(isNaN(popH)) {popH = 0;}if (popH==0){MsgPop.style.display="block";show=setInterval("changeH('up')",100);}else {hide=setInterval("changeH('down')",100);}}function changeH(str) {var MsgPop=document.getElementById("winpop");var popH=parseInt(MsgPop.style.height);if(isNaN(popH)) {popH = 0;}if(str=="up"){ if (popH<=100){ MsgPop.style.height=(popH+4).toString()+"px";}else{ clearInterval(show);setTimeout("tips_pop()", 5000);}}if(str=="down"){ if (popH>=4){ MsgPop.style.height=(popH-4).toString()+"px";}else{ clearInterval(hide); MsgPop.style.display="none"; }}}// WebSocket相關var ws = null;function connect() {var target = 'ws://' + window.location.host + "/test/NotifyWebSocketServlet";if ('WebSocket' in window) {ws = new WebSocket(target);} else if ('MozWebSocket' in window) {ws = new MozWebSocket(target);} else {alert('WebSocket is not supported by this browser.');return;}ws.onopen = function () {document.getElementById('msg').innerHTML = "WebSocket has opened, Waiting message.......";};ws.onmessage = function (event) {document.getElementById('infomsg').innerHTML = event.data;tips_pop();};ws.onclose = function () {document.getElementById('msg').innerHTML = "WebSocket has closed";};}function disconnect() {if (ws != null) {ws.close();ws = null;}} connect(); </script> </head> <body><h1 align="center" id="msg">Try to connect websocket.</h1><div id="winpop"><div class="con" id="infomsg"></div></div> </body> </html>
??????? 當用戶界面打開時,它會嘗試通過/test/NotifyWebSocketServlet建立與server的WebSocket連接,而NotifyWebSocketServlet的實現代碼則例如以下: package net.yanzhijun.example;import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest;import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet;public class NotifyWebSocketServlet extends WebSocketServlet {private static final long serialVersionUID = 1L; @Overrideprotected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request) {ServletContext application = this.getServletContext();return new NofityMessageInbound(application);} }

??????? 與Tomcat給出的演示樣例代碼不同的是,在NotifyWebSocketServlet中并未將繼承于MessageInboundNofityMessageInbound作為一個內嵌類。前述演示樣例代碼中發送消息和接收消息都是在同一組client頁面和服務端響應Servlet間進行的,而當前須要實現是在一個頁面中提交通知,而在其他用戶的頁面上顯示通知信息,因此須要將全部client與服務端的連接存儲一個全局域中,故而NofityMessageInbound將不僅僅在當前Servlet中被使用,所以有必要將其獨立出來。

??????? NofityMessageInbound的完整代碼例如以下: package net.yanzhijun.example;import java.nio.CharBuffer; import java.nio.ByteBuffer; import java.io.IOException; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet;import javax.servlet.ServletContext;import org.apache.catalina.websocket.WsOutbound; import org.apache.catalina.websocket.MessageInbound;public class NofityMessageInbound extends MessageInbound {private ServletContext application;private Set<NofityMessageInbound> connections = null;public NofityMessageInbound(ServletContext application) {this.application = application;connections = (Set<NofityMessageInbound>)application.getAttribute("connections");if(connections == null) {connections =new CopyOnWriteArraySet<NofityMessageInbound>();}}@Overrideprotected void onOpen(WsOutbound outbound) {connections.add(this); application.setAttribute("connections", connections);}@Overrideprotected void onClose(int status) {connections.remove(this);application.setAttribute("connections", connections);}@Overrideprotected void onBinaryMessage(ByteBuffer message) throws IOException {throw new UnsupportedOperationException("message not supported.");}@Overrideprotected void onTextMessage(CharBuffer message) throws IOException {throw new UnsupportedOperationException("message not supported.");} }
??????? 后臺發送通知的頁面實現的相當簡單,僅僅是一個表單提交一條通知信息。 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>PushMessage</title></head><body><h1 align="Center">Online Broadcast</h1><form method="post" action="PushMessageServlet"><p>Message:<br/><textarea name="message" rows="5" cols="30"></textarea></p><p><input type="submit" value="Send">??<input type="reset" value="Reset"></p></form></body> </html>
?????? 接收提交通知的Servlet是PushMessageServlet,它在收到后臺提交的通知后,就通過全部用戶的WebSocket連接將通知發送出去。 package net.yanzhijun.example;import java.io.PrintWriter; import java.nio.CharBuffer; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.io.IOException;import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class PushMessageServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overridepublic void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException {doPost(request, response);}@Overridepublic void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();String message = request.getParameter("message"); if(message == null || message.length() == 0) { out.println("The message is empty!");return;}// 廣播消息broadcast(message);out.println("Send success!"); }// 將參數中的消息發送至全部在線clientprivate void broadcast(String message) {ServletContext application=this.getServletContext(); Set<NofityMessageInbound> connections = (Set<NofityMessageInbound>)application.getAttribute("connections");if(connections == null){return;}for (NofityMessageInbound connection : connections) {try {CharBuffer buffer = CharBuffer.wrap(message);connection.getWsOutbound().writeTextMessage(buffer);} catch (IOException ignore) {// Ignore}}} }
??????? 編譯相關文件并完畢部署,嘗試在后臺發送消息,能夠看到用戶界面右下角出現的彈窗中顯示了后臺所提交的內容。 ????????????????????????????????????????????????? 圖4

五、????????????WebSocket總結

????通過以上例程和實例能夠看出,從開發角度使用WebSocket相當easy,基本僅僅須要創建WebSocket實例并對關心的事件進行處理就能夠了;從應用角度WebSocket提供了優異的性能,圖 5是來自websocket.org的性能測試圖表(http://www.websocket.org/quantum.html),能夠看到當并發和負載添加時輪詢與WebSocket的差異。 ?????????????????????????????????????????????????????????????????? 圖5 ???????? (以上例程client在IE10.0和Chrom28.0下測試通過。) ? ???????? 歡迎訪問夢斷酒醒的博客http://blog.csdn.net/ishallwn

總結

以上是生活随笔為你收集整理的【WebSocket初探】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 成人日皮视频 | 揄拍成人国产精品视频 | 欧美一级在线看 | 成人h在线 | av自拍网 | 三级91 | 国产精品久久久久91 | 日产精品久久久 | 少妇aa | 亚洲系列| 三区在线视频 | 丰满少妇被猛烈进入一区二区 | 日韩一级黄色片 | 台湾swag在线观看 | 一区二区三区四区高清视频 | 天天干中文字幕 | 午夜伦理视频 | 午夜久久 | 亚洲国产麻豆 | 一级欧美日韩 | 香蕉视频官网 | 国产99精品视频 | 久久久久一区二区三区 | 色诱久久av | 欧美日韩第一页 | 色欧美在线 | 国产丝袜一区二区 | 91成人入口 | 国产精品影院在线观看 | 九九热在线免费视频 | 亚洲精品一区在线 | 日本亲与子乱ay中文 | 精产国产伦理一二三区 | 精品一区二区三区视频在线观看 | 18黄暴禁片在线观看 | 天堂www中文在线资源 | 美女黄色一级 | 精品亚洲综合 | 男女爱爱福利视频 | 国产美女在线播放 | 毛片毛片毛片毛片毛片毛片 | 伊人久久中文字幕 | 国内成人自拍 | www.综合色| 女同在线观看 | 波多野结衣在线一区二区 | 在线精品福利 | 亚洲综合久久av一区二区三区 | 日韩aⅴ片 | 超薄肉色丝袜一区二区 | 久草视频福利在线 | 久草福利在线视频 | 超碰97在线资源 | 国产精品500部 | 黄色免费小视频 | 久久黄色片 | 人妖和人妖互交性xxxx视频 | 欧美在线免费 | 尤物毛片| 男生女生羞羞网站 | 夜夜爽夜夜操 | 免费视频黄色 | 国产a免费观看 | 好吊色视频一区二区三区 | av中文字幕免费观看 | 欧美激情亚洲色图 | 亚洲欧美第一视频 | 男人的影院 | 国产一区二区电影 | 天天视频污 | 亚洲一区二区不卡视频 | 91麻豆映画传媒 | a级黄片毛片 | 四虎免费网址 | 久久国产精彩视频 | 中文字幕淫 | 国产伦精品免费视频 | 老鸭窝视频在线观看 | 亚洲性生活片 | 欧美日本韩国一区二区三区 | 九七伦理电影 | 久久久久亚洲av成人网人人软件 | 国产成人精品亚洲精品色欲 | 国产精品久久久久久婷婷天堂 | 国产午夜性春猛交ⅹxxx | 成人性视频网 | 一区二区不卡在线 | 国产午夜精品久久久久久久久久 | 亚洲免费高清 | 国产一区二区av | 尹人综合在线 | 日韩中出在线 | 又大又粗欧美黑人aaaaa片 | 91在线观看免费高清 | 18禁免费观看网站 | 国产极品美女在线 | 永久福利视频 | 亚洲国产电影在线观看 | 一二区免费视频 |