精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

聊聊分布式下的WebSocket解決方案

開發 前端 分布式
最近自己搭建了個項目,項目本身很簡單,但是里面有使用WebSocket進行消息提醒的功能,大體情況是這樣的。發布消息者在系統中發送消息,實時的把消息推送給對應的一個部門下的所有人。

前言

最近自己搭建了個項目,項目本身很簡單,但是里面有使用WebSocket進行消息提醒的功能,大體情況是這樣的。

發布消息者在系統中發送消息,實時的把消息推送給對應的一個部門下的所有人。

這里面如果是單機應用的情況時,我們可以通過部門的id和用戶的id組成一個唯一的key,與應用服務器建立WebSocket長連接,然后就可以接收到發布消息者發送的消息了。

但是真正把項目應用于生產環境中時,我們是不可能就部署一個單機應用的,而是要部署一個集群。

[[343393]]

所以我通過Nginx+兩臺Tomcat搭建了一個簡單的負載均衡集群,作為測試使用

但是問題出現了,我們的客戶端瀏覽器只會與一臺服務器建立WebSocket長連接,所以發布消息者在發送消息時,就沒法保證所有目標部門的人都能接收到消息(因為這些人連接的可能不是一個服務器)。

本篇文章就是針對于這么一個問題展開討論,提出一種解決方案,當然解決方案不止一種,那我們開始吧。

WebSocket單體應用介紹

在介紹分布式集群之前,我們先來看一下王子的WebSocket代碼實現,先來看java后端代碼如下:

  1. import javax.websocket.*; 
  2. import javax.websocket.server.PathParam; 
  3. import javax.websocket.server.ServerEndpoint; 
  4. import com.alibaba.fastjson.JSON; 
  5. import com.alibaba.fastjson.JSONObject;import java.io.IOException; 
  6. import java.util.Map; 
  7. import java.util.concurrent.ConcurrentHashMap; 
  8. @ServerEndpoint("/webSocket/{key}"
  9. public class WebSocket { 
  10.     private static int onlineCount = 0; 
  11.     /** 
  12.      * 存儲連接的客戶端 
  13.      */ 
  14.     private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>(); 
  15.     private Session session; 
  16.     /** 
  17.      * 發送的目標科室code 
  18.      */ 
  19.     private String key
  20.     @OnOpen 
  21.     public void onOpen(@PathParam("key") String key, Session session) throws IOException { 
  22.         this.key = key
  23.         this.session = session; 
  24.         if (!clients.containsKey(key)) { 
  25.             addOnlineCount();        }        clients.put(key, this); 
  26.         Log.info(key+"已連接消息服務!"); 
  27.     }    @OnClose 
  28.     public void onClose() throws IOException { 
  29.         clients.remove(key);        subOnlineCount();    }    @OnMessage 
  30.     public void onMessage(String message) throws IOException { 
  31.         if(message.equals("ping")){ 
  32.             return ; 
  33.         }        JSONObject jsonTo = JSON.parseObject(message);        String mes = (String) jsonTo.get("message"); 
  34.         if (!jsonTo.get("to").equals("All")){ 
  35.             sendMessageTo(mes, jsonTo.get("to").toString()); 
  36.         }else
  37.             sendMessageAll(mes);        }    }    @OnError 
  38.     public void onError(Session session, Throwable error) { 
  39.         error.printStackTrace();    }    private void sendMessageTo(String message, String To) throws IOException { 
  40.         for (WebSocket item : clients.values()) { 
  41.             if (item.key.contains(To) ) 
  42.                 item.session.getAsyncRemote().sendText(message);        }    }    private void sendMessageAll(String message) throws IOException { 
  43.         for (WebSocket item : clients.values()) { 
  44.             item.session.getAsyncRemote().sendText(message);        }    }    public static synchronized int getOnlineCount() { 
  45.         return onlineCount; 
  46.     }    public static synchronized void addOnlineCount() { 
  47.         WebSocket.onlineCount++;    }    public static synchronized void subOnlineCount() { 
  48.         WebSocket.onlineCount--;    }    public static synchronized Map<String, WebSocket> getClients() { 
  49.         return clients; 
  50.     }} 

示例代碼中并沒有使用Spring,用的是原生的java web編寫的,簡單和大家介紹一下里面的方法。

  • onOpen:在客戶端與WebSocket服務連接時觸發方法執行
  • onClose:在客戶端與WebSocket連接斷開的時候觸發執行
  • onMessage:在接收到客戶端發送的消息時觸發執行
  • onError:在發生錯誤時觸發執行

可以看到,在onMessage方法中,我們直接根據客戶端發送的消息,進行消息的轉發功能,這樣在單體消息服務中是沒有問題的。

再來看一下js代碼

  1. var host = document.location.host; 
  2.     // 獲得當前登錄科室    var deptCodes='${sessionScope.$UserContext.departmentID}'
  3.     deptCodes=deptCodes.replace(/[\[|\]|\s]+/g, ""); 
  4.     var key = '${sessionScope.$UserContext.userID}'+deptCodes; 
  5.     var lockReconnect = false;  //避免ws重復連接 
  6.     var ws = null;          // 判斷當前瀏覽器是否支持WebSocket    var wsUrl = 'ws://' + host + '/webSocket/'key
  7.     createWebSocket(wsUrl);   //連接ws    function createWebSocket(url) { 
  8.         try{            if('WebSocket' in window){ 
  9.                 ws = new WebSocket(url);            }else if('MozWebSocket' in window){   
  10.                 ws = new MozWebSocket(url);            }else
  11.                   layer.alert("您的瀏覽器不支持websocket協議,建議使用新版谷歌、火狐等瀏覽器,請勿使用IE10以下瀏覽器,360瀏覽器請使用極速模式,不要使用兼容模式!");  
  12.             }            initEventHandle();        }catch(e){            reconnect(url);            console.log(e); 
  13.         }         }    function initEventHandle() { 
  14.         ws.onclose = function () { 
  15.             reconnect(wsUrl);            console.log("llws連接關閉!"+new Date().toUTCString()); 
  16.         };        ws.onerror = function () { 
  17.             reconnect(wsUrl);            console.log("llws連接錯誤!"); 
  18.         };        ws.onopen = function () { 
  19.             heartCheck.reset().start();      //心跳檢測重置            console.log("llws連接成功!"+new Date().toUTCString()); 
  20.         };        ws.onmessage = function (event) {    //如果獲取到消息,心跳檢測重置 
  21.             heartCheck.reset().start();      //拿到任何消息都說明當前連接是正常的//接收到消息實際業務處理        ...        };    }    // 監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。    window.onbeforeunload = function() { 
  22.         ws.close(); 
  23.     }      function reconnect(url) { 
  24.         if(lockReconnect) return
  25.         lockReconnect = true
  26.         setTimeout(function () {     //沒連接上會一直重連,設置延遲避免請求過多 
  27.             createWebSocket(url);            lockReconnect = false
  28.         }, 2000); 
  29.     }    //心跳檢測    var heartCheck = {        timeout: 300000,        //5分鐘發一次心跳 
  30.         timeoutObj: null,        serverTimeoutObj: null,        reset: function(){ 
  31.             clearTimeout(this.timeoutObj);            clearTimeout(this.serverTimeoutObj);            return this; 
  32.         },        start: function(){ 
  33.             var self = this;            this.timeoutObj = setTimeout(function(){ 
  34.                 //這里發送一個心跳,后端收到后,返回一個心跳消息,                //onmessage拿到返回的心跳就說明連接正常                ws.send("ping"); 
  35.                 console.log("ping!"
  36.                 self.serverTimeoutObj = setTimeout(function(){//如果超過一定時間還沒重置,說明后端主動斷開了 
  37.                     ws.close();     //如果onclose會執行reconnect,我們執行ws.close()就行了.如果直接執行reconnect 會觸發onclose導致重連兩次 
  38.                 }, self.timeout)            }, this.timeout)        }  } 

js部分使用的是原生H5編寫的,如果為了更好的兼容瀏覽器,也可以使用SockJS,有興趣小伙伴們可以自行百度。

接下來我們就手動的優化代碼,實現WebSocket對分布式架構的支持。

解決方案的思考

現在我們已經了解單體應用下的代碼結構,也清楚了WebSocket在分布式環境下面臨的問題,那么是時候思考一下如何能夠解決這個問題了。

我們先來看一看發生這個問題的根本原因是什么。

簡單思考一下就能明白,單體應用下只有一臺服務器,所有的客戶端連接的都是這一臺消息服務器,所以當發布消息者發送消息時,所有的客戶端其實已經全部與這臺服務器建立了連接,直接群發消息就可以了。

換成分布式系統后,假如我們有兩臺消息服務器,那么客戶端通過Nginx負載均衡后,就會有一部分連接到其中一臺服務器,另一部分連接到另一臺服務器,所以發布消息者發送消息時,只會發送到其中的一臺服務器上,而這臺消息服務器就可以執行群發操作,但問題是,另一臺服務器并不知道這件事,也就無法發送消息了。

現在我們知道了根本原因是生產消息時,只有一臺消息服務器能夠感知到,所以我們只要讓另一臺消息服務器也能感知到就可以了,這樣感知到之后,它就可以群發消息給連接到它上邊的客戶端了。

那么什么方法可以實現這種功能呢,王子很快想到了引入消息中間件,并使用它的發布訂閱模式來通知所有消息服務器就可以了。

引入RabbitMQ解決分布式下的WebSocket問題

在消息中間件的選擇上,王子選擇了RabbitMQ,原因是它的搭建比較簡單,功能也很強大,而且我們只是用到它群發消息的功能。

RabbitMQ有一個廣播模式(fanout),我們使用的就是這種模式。

首先我們寫一個RabbitMQ的連接類:

  1. import com.rabbitmq.client.Connection
  2. import com.rabbitmq.client.ConnectionFactory; 
  3. import java.io.IOException; 
  4. import java.util.concurrent.TimeoutException; 
  5. public class RabbitMQUtil { 
  6.     private static Connection connection
  7.     /** 
  8.      * 與rabbitmq建立連接 
  9.      * @return 
  10.      */ 
  11.     public static Connection getConnection() { 
  12.         if (connection != null&&connection.isOpen()) { 
  13.             return connection
  14.         }        ConnectionFactory factory = new ConnectionFactory(); 
  15.         factory.setVirtualHost("/"); 
  16.         factory.setHost("192.168.220.110"); // 用的是虛擬IP地址 
  17.         factory.setPort(5672); 
  18.         factory.setUsername("guest"); 
  19.         factory.setPassword("guest"); 
  20.         try { 
  21.             connection = factory.newConnection(); 
  22.         } catch (IOException e) { 
  23.             e.printStackTrace(); 
  24.         } catch (TimeoutException e) { 
  25.             e.printStackTrace(); 
  26.         } 
  27.         return connection
  28.     } 

這個類沒什么說的,就是獲取MQ連接的一個工廠類。

然后按照我們的思路,就是每次服務器啟動的時候,都會創建一個MQ的消費者監聽MQ的消息,王子這里測試使用的是Servlet的監聽器,如下:

  1. import javax.servlet.ServletContextEvent; 
  2. import javax.servlet.ServletContextListener; 
  3. public class InitListener implements ServletContextListener { 
  4.     @Override 
  5.     public void contextInitialized(ServletContextEvent servletContextEvent) { 
  6.         WebSocket.init();    }    @Override 
  7.     public void contextDestroyed(ServletContextEvent servletContextEvent) { 
  8.     }} 

記得要在Web.xml中配置監聽器信息

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4.          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 
  5.          version="4.0"
  6.     <listener> 
  7.         <listener-class>InitListener</listener-class> 
  8.     </listener> 
  9. </web-app> 

WebSocket中增加init方法,作為MQ消費者部分

  1. public  static void init() { 
  2.         try {            Connection connection = RabbitMQUtil.getConnection();            Channel channel = connection.createChannel();            //交換機聲明(參數為:交換機名稱;交換機類型) 
  3.             channel.exchangeDeclare("fanoutLogs",BuiltinExchangeType.FANOUT); 
  4.             //獲取一個臨時隊列 
  5.             String queueName = channel.queueDeclare().getQueue();            //隊列與交換機綁定(參數為:隊列名稱;交換機名稱;routingKey忽略) 
  6.             channel.queueBind(queueName,"fanoutLogs",""); 
  7.             //這里重寫了DefaultConsumer的handleDelivery方法,因為發送的時候對消息進行了getByte(),在這里要重新組裝成String 
  8.             Consumer consumer = new DefaultConsumer(channel) {                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    super.handleDelivery(consumerTag, envelope, properties, body); 
  9.                     String message = new String(body,"UTF-8"); 
  10.                     System.out.println(message);            //這里可以使用WebSocket通過消息內容發送消息給對應的客戶端 
  11.                 }            };            //聲明隊列中被消費掉的消息(參數為:隊列名稱;消息是否自動確認;consumer主體) 
  12.             channel.basicConsume(queueName,true,consumer); 
  13.             //這里不能關閉連接,調用了消費方法后,消費者會一直連接著rabbitMQ等待消費 
  14.         } catch (IOException e) {            e.printStackTrace();        }    } 

同時在接收到消息時,不是直接通過WebSocket發送消息給對應客戶端,而是發送消息給MQ,這樣如果消息服務器有多個,就都會從MQ中獲得消息,之后通過獲取的消息內容再使用WebSocket推送給對應的客戶端就可以了。

WebSocket的onMessage方法增加內容如下:

  1. try { 
  2.             //嘗試獲取一個連接 
  3.             Connection connection = RabbitMQUtil.getConnection();            //嘗試創建一個channel 
  4.             Channel channel = connection.createChannel();            //聲明交換機(參數為:交換機名稱; 交換機類型,廣播模式) 
  5.             channel.exchangeDeclare("fanoutLogs", BuiltinExchangeType.FANOUT); 
  6.             //消息發布(參數為:交換機名稱; routingKey,忽略。在廣播模式中,生產者聲明交換機的名稱和類型即可) 
  7.             channel.basicPublish("fanoutLogs",""null,msg.getBytes("UTF-8")); 
  8.             System.out.println("發布消息"); 
  9.             channel.close();        } catch (IOException |TimeoutException e) { 
  10.             e.printStackTrace(); 
  11.         } 

增加后刪除掉原來的Websocket推送部分代碼。

這樣一整套的解決方案就完成了。

總結

到這里,我們就解決了分布式下WebSocket的推送消息問題。

我們主要是引入了RabbitMQ,通過RabbitMQ的發布訂閱模式,讓每個消息服務器啟動的時候都去訂閱消息,而無論哪臺消息服務器在發送消息的時候都會發送給MQ,這樣每臺消息服務器就都會感知到發送消息的時間,從而再通過Websocket發送給客戶端。

大體流程就是這樣,那么小伙伴們有沒有想過,如果RabbitMQ掛掉了幾分鐘,之后重啟了,消費者是否可以重新連接到RabbitMQ?是否還能正常接收消息呢?

生產環境下,這個問題是必須考慮的。

這里已經測試過,消費者是支持自動重連的,所以我們可以放心的使用這套架構來解決此問題。

本文到這里就結束了,歡迎各位小伙伴留言討論,一起學習,一起進步。

責任編輯:未麗燕 來源: 今日頭條
相關推薦

2021-09-28 09:43:11

微服務架構技術

2023-03-05 18:23:38

分布式ID節點

2025-04-28 00:44:04

2023-09-14 15:44:46

分布式事務數據存儲

2020-05-28 09:35:05

分布式事務方案

2025-04-29 04:00:00

分布式事務事務消息

2010-07-21 13:53:41

SQL Server分

2025-05-07 00:10:00

分布式事務TCC模式

2022-09-07 08:18:26

分布式灰度方案分支號

2024-03-26 12:08:53

分布式事務存儲

2023-11-30 07:19:08

.NET開源

2018-07-19 14:53:23

秒殺websocket異步

2021-05-08 08:01:05

Session登錄瀏覽器

2025-06-30 07:15:32

.NET應用分布式

2022-02-10 08:57:45

分布式線程鎖

2024-06-13 08:04:23

2023-05-18 14:02:00

分布式系統冪等性

2019-01-11 18:22:07

阿里巴巴技術開源

2023-09-28 08:39:23

分布式鎖Redis

2021-06-28 10:03:44

分布式數據庫架構
點贊
收藏

51CTO技術棧公眾號

啊v视频在线| 国产美女免费网站| 免费影视亚洲| 精品成人18| 九一久久久久久| 久久久国产精品x99av| 久久久久久久久久毛片| 都市激情久久综合| 国产无一区二区| 国产成人一区二区在线观看| 中文字幕av网站| 国产女人高潮毛片| 欧洲杯足球赛直播| 欧美日韩精品一区二区三区四区| 大地资源网在线观看免费官网| 亚洲精品久久久狠狠狠爱| 日韩一级在线| 日韩中文理论片| 国产精品扒开腿做爽爽爽a片唱戏| 亚洲精品国产精品国产| 日韩理论片网站| 乱色588欧美| 国产黄a三级三级看三级| 亚洲在线一区| 九色91av视频| 一级肉体全黄裸片| 黑色丝袜福利片av久久| 在线播放中文字幕一区| 男人的天堂avav| 久久天堂电影| 国产高清久久久| 国产精品成人一区| 日韩精品一卡二卡| 中文字幕日韩欧美精品高清在线| 日本成人黄色片| 精品人妻无码一区二区三区| aa级大片免费在线观看| 中文在线免费一区三区高中清不卡| 2014国产精品| 瑟瑟视频在线免费观看| 盗摄牛牛av影视一区二区| 美女一区二区久久| 欧美性在线观看| 久久免费看少妇高潮v片特黄| 蜜桃一区二区三区| 亚洲国产精品va在线| 91亚洲一区二区| 佐佐木明希电影| 91theporn国产在线观看| 国内精品久久久久久久影视蜜臀| 中文字幕av一区二区三区谷原希美| jjzz黄色片| 天堂综合在线播放| 91久久精品网| 国产精品一区在线播放| 亚洲色婷婷一区二区三区| 国产麻豆一区二区三区精品视频| 精品国产乱码久久| 亚洲精品鲁一鲁一区二区三区| 久久亚洲精品人成综合网| 日本道色综合久久| 日韩日本欧美亚洲| 中文字幕一区二区三区人妻| 黄色美女久久久| 亚洲精品在线观看网站| 成人做爰www看视频软件| 日韩在线观看一区二区三区| 91精品国产综合久久蜜臀| 男人的天堂最新网址| 巨大黑人极品videos精品| 欧美日韩在线亚洲一区蜜芽| 九色porny自拍| 激情久久一区二区| 宅男噜噜噜66一区二区66| 欧美国产日韩另类| 日韩一区二区三区精品| 精品国产一区a| 中文字幕在线永久| 国产欧美日韩视频在线| 在线视频欧美日韩| 中文乱码字幕高清一区二区| 91精品一区二区三区综合在线爱| 精品少妇v888av| 欧美日韩中文视频| 久久精品123| 国产精品视频一区二区三区四| 亚洲一区二区人妻| 国产精品综合在线视频| 国产一区二区三区四区五区加勒比| 日本精品一区二区在线观看| 久久午夜色播影院免费高清| 日韩免费中文专区| 高清全集视频免费在线| 亚洲愉拍自拍另类高清精品| 国产va亚洲va在线va| 欧美少妇网站| 欧美日韩专区在线| 久久黄色一级视频| 亚洲成aⅴ人片久久青草影院| 国产亚洲美女精品久久久| 三级黄色录像视频| 亚洲国产专区| 国产精品久久久久久婷婷天堂| 国产又粗又猛又黄| 不卡高清视频专区| 日本精品一区二区三区视频| av在线影院| 日韩欧美成人免费视频| 亚洲天堂伊人网| 日韩欧美在线精品| 久久久精品电影| 日韩不卡在线播放| 国产91色综合久久免费分享| 先锋影音亚洲资源| www.超碰在线| 69p69国产精品| 久久精品一区二区免费播放| 自产国语精品视频| 国产激情视频一区| 日本xxxxwww| 中文字幕在线观看不卡视频| 免费观看日韩毛片| 亚洲性视频在线| 亚洲性夜色噜噜噜7777| 精品少妇爆乳无码av无码专区| 久久国产精品无码网站| 精品国产二区在线| 日本中文字幕在线视频观看| 九九热线视频只有这里最精品| 欧美变态凌虐bdsm| 亚洲国产精品一区二区久久hs| 中文精品在线| 成人h视频在线观看| 成人影院免费观看| 一本色道久久综合亚洲aⅴ蜜桃| 日韩欧美色视频| 欧美一区二区女人| 一区二区xxx| 婷婷国产精品| 欧美精品电影在线| 国产福利视频导航| 最新欧美精品一区二区三区| 国产精品拍拍拍| 天天操综合520| 久久久久国产精品一区| 人成网站在线观看| 国产精品卡一卡二| 熟女少妇精品一区二区| 思热99re视热频这里只精品| 欧美美女15p| 国产精品午夜福利| 国产精品日韩成人| 91极品尤物在线播放国产| 欧美精品中文字幕亚洲专区| 亚洲精品视频免费| 亚洲av成人片色在线观看高潮| 亚洲一区二区三区无吗| 国产在线观看不卡| 在线毛片网站| 欧美天堂一区二区三区| 久久久久亚洲av无码a片| 日韩精品亚洲一区| 美腿丝袜在线亚洲一区| 久久久久久久久四区三区| 高清在线视频不卡| 亚洲黄色av网站| 日韩av电影网| 成人免费视频免费观看| 成人免费视频91| 国产精品久久久久久久久久白浆 | 中文字幕亚洲欧美日韩高清| 日本a级c片免费看三区| 国产女人18毛片水真多成人如厕| 亚洲成熟丰满熟妇高潮xxxxx| 极品美女一区二区三区| 国产欧美一区二区| 天堂av资源在线观看| 精品国产免费一区二区三区四区 | 久久久亚洲影院| 天堂中文网在线| 日韩欧美成人精品| 亚洲欧美卡通动漫| 成人免费视频app| 美女av免费在线观看| 久久密一区二区三区| 51午夜精品| 色偷偷偷在线视频播放| 在线观看日韩av| 国产wwwwwww| 香蕉影视欧美成人| www.日本高清视频| 国产精品自拍一区| 成人羞羞国产免费网站| 国产电影一区二区在线观看| 国产日韩一区欧美| 91在线亚洲| 欧美高跟鞋交xxxxxhd| 免费黄网站在线观看| 制服丝袜中文字幕亚洲| 日干夜干天天干| 亚洲欧洲精品成人久久奇米网| 精品国产免费久久久久久婷婷| 在线亚洲欧美| 日本不卡一区二区三区四区| 你懂的在线观看一区二区| 国产免费观看久久黄| f2c人成在线观看免费视频| 中文字幕日韩av电影| 蜜臀久久精品久久久久| 欧美日韩在线播放| 国产九色在线播放九色| 亚洲欧美另类小说| 亚洲精品色午夜无码专区日韩| 国产成人亚洲综合a∨猫咪| 男人天堂成人在线| 亚洲激情社区| 日本成人性视频| 久操国产精品| 国产精品swag| 亚洲毛片在线免费| 国产精品吹潮在线观看| 国内激情视频在线观看| 精品中文字幕在线2019| 波多野结衣在线网站| 日韩精品一区二区视频| 成人免费一级视频| 制服丝袜亚洲播放| 国产精品欧美综合| 一本大道久久a久久综合婷婷| 精品一区在线视频| 亚洲视频免费在线观看| av永久免费观看| 91在线观看高清| 国产女主播在线播放| 精品一区二区三区视频在线观看| 欧美日韩在线不卡视频| 在线播放一区| 黄色小视频大全| 91麻豆精品国产91久久久平台| 亚洲欧美综合久久久| 日韩国产成人在线| 国产三级久久久| 国产精品久久无码| 国产a精品视频| 成人高清在线观看视频| 精品一区二区精品| 中文字幕第17页| 24小时免费看片在线观看 | 成人免费在线视频网| 亚洲黄色在线观看| 天天插天天干天天操| 亚洲成人黄色网址| 人妻少妇精品无码专区| 精品女同一区二区| 日韩一区二区三区不卡| 亚洲国产精彩中文乱码av| 免费av网站观看| 亚洲国产成人精品女人久久久| 韩国av在线免费观看| 亚洲丁香久久久| 日韩一级免费毛片| 亚洲欧美精品一区二区| 精品成人一区二区三区免费视频| 亚洲欧美制服另类日韩| 国产精品四虎| 中文国产成人精品久久一| 日韩理伦片在线| 久久久精品国产亚洲| 成人无遮挡免费网站视频在线观看| 美女福利精品视频| 国内老司机av在线| 91国语精品自产拍在线观看性色| 色多多在线观看| 国产精品精品视频一区二区三区| 91精品店在线| 91免费欧美精品| 日韩精品成人在线观看| 国产欧美欧洲| 国产亚洲精品美女久久久久久久久久| 日韩成人av电影在线| 亚洲成人精品| www.在线观看av| 免费在线亚洲| 亚洲xxxx2d动漫1| 国产高清精品网站| 国产精品九九九九九| 亚洲欧洲精品成人久久奇米网| 国产在线观看免费av| 色婷婷综合久久久久中文一区二区 | 91精品韩国| 91久久夜色精品国产网站| 国产精品超碰| 日韩欧美一区二区三区四区五区| 911精品美国片911久久久| 欧洲精品一区二区三区久久| 蜜乳av另类精品一区二区| 午夜啪啪小视频| 91丨九色丨蝌蚪丨老版| 免费观看特级毛片| 性欧美大战久久久久久久久| 中文字幕第一页在线播放| 欧美哺乳videos| seseavlu视频在线| 国产做受高潮69| 国产精品亚洲成在人线| 激情视频在线观看一区二区三区| 全球成人免费直播| 色老汉av一区二区三区| 精品视频久久久久| 欧美日韩视频在线观看一区二区三区 | 亚洲欧美在线专区| 日本成人在线免费视频| 美女尤物国产一区| 国产伦精品一区二区三区妓女| 国产精品美女一区二区三区| 日本网站在线播放| 91精品婷婷国产综合久久竹菊| 日本视频在线观看一区二区三区| 久久这里只有精品99| 成人日韩在线观看| 激情视频一区二区| 欧美日韩午夜| 国产九九在线观看| 久久综合九色综合97婷婷女人| 国产大学生自拍| 欧美在线你懂得| 视频二区在线| 欧美激情视频免费观看| 国产欧美日韩电影| 日韩中文字幕一区二区| 亚洲资源av| 少妇激情一区二区三区视频| 亚洲欧美日韩中文字幕一区二区三区 | 亚洲欧洲日韩国产| av在线不卡免费| 亚洲一区免费网站| 99久久亚洲精品蜜臀| 青青青在线视频免费观看| 久久综合久久综合久久综合| 久草免费新视频| 91精品免费在线观看| 自拍视频在线免费观看| 日本亚洲欧洲色α| 亚洲精品国产setv| 成熟丰满熟妇高潮xxxxx视频| 国产99久久久精品| 欧美成人黄色网| 3751色影院一区二区三区| 米奇777四色精品人人爽| 国产精品免费久久久| 欧美日韩在线二区| 激情视频综合网| 国产日产欧美精品一区二区三区| 国产区一区二区三| 久久精品二区| 2001个疯子在线观看| 99re视频在线播放| 欧美特黄视频| 欧美一级大片免费看| 一区二区在线看| av老司机久久| 久久成人精品视频| 国产一区二区三区| 777久久精品一区二区三区无码| 狠狠色丁香久久婷婷综合_中| 四虎地址8848| 91精品国产色综合久久久蜜香臀| 国产一二区在线| 亚洲www视频| 韩国自拍一区| 偷偷色噜狠狠狠狠的777米奇| 精品欧美一区二区三区| 国产在线一二三区| 国产美女91呻吟求| 欧美在线1区| 中文字幕乱码一区| 在线观看欧美黄色| 黄网址在线观看| 国产福利久久精品| 久久精品动漫| 黑人狂躁日本娇小| 日韩一级完整毛片| 69av成人| 日韩色妇久久av| 国内成人自拍视频| 日韩成人免费在线视频| 亚洲人高潮女人毛茸茸| 青青在线精品| 日韩精品在线中文字幕| 久久久久久一二三区| 亚洲天堂国产精品| 国内精品久久久久影院优| 性欧美lx╳lx╳| 精品久久久99| 红桃视频成人在线观看| 91成人高清| 国产欧美韩日| 精品中文av资源站在线观看| 国产精品99re| 一区二区欧美亚洲|