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

基于Java NIO的即時聊天服務器模型

開發 后端
折騰了一個周,終于搞出來了一個雛形,相比于xmpp的xml,本人更喜歡json的簡潔,為了防止客戶端異常斷開等,準備采用心跳檢測的機制來判斷用戶是否在線,另外還有一種方法是學習例如Tomcat等Servlet中間件的方式,設置Session周期,定時清除過期Session。

前不久自己動手寫了一個Android的聊天工具,跟服務器的交互還是基于HTTP方式的,在一般通訊上還算湊活,但是在即時聊天的時候就有點惡心了,客戶端開啟Service每隔3秒去詢問服務器是否有自己的新消息(當然3秒有點太快了),在心疼性能和流量的前提下,只能自己動手寫個服務器,傳統的Socket是阻塞的,這樣的話服務器對每個Socket都需要建立一個線程來操作,資源開銷很大,而且線程多了直接會影響服務端的性能(曾經測試開了3000多個線程就不讓創建了,所以并發數目也是有限制的),聽說從JDK1.5就多了個New IO,灰常不錯的樣子,找了找相關的資料,網上竟然全都是最最最簡單的一個demo,然后去CSDN發帖,基本上都是建議直接使用MINA框架的,這樣一來根本達不到學習NIO的目的,而且現在的技術也太快餐了,只知道使用前輩留下的東西,知其然不知其所以然。

折騰了一個周,終于搞出來了一個雛形,相比于xmpp的xml,本人更喜歡json的簡潔,為了防止客戶端異常斷開等,準備采用心跳檢測的機制來判斷用戶是否在線,另外還有一種方法是學習例如Tomcat等Servlet中間件的方式,設置Session周期,定時清除過期Session。本Demo暫時實現了Session過期檢測,心跳檢測有空再搞,如果本例子在使用過程中有性能漏洞或者什么bug請及時通知我,謝謝。

廢話不多說,關于NIO的SelectionKey、Selector、Channel網上的介紹例子都很多,直接上代碼:

JsonParser

Json的解析類,隨便封裝了下,使用的最近比較火的fastjson

  1. public class JsonParser { 
  2.      
  3.     private static JSONObject mJson; 
  4.      
  5.     public synchronized static String get(String json,String key) { 
  6.         mJson = JSON.parseObject(json); 
  7.         return mJson.getString(key); 
  8.     } 

Main

入口,不解釋

  1. public class Main { 
  2.  
  3.     public static void main(String... args) { 
  4.         new SeekServer().start(); 
  5.     } 

Log

  1. public class Log { 
  2.  
  3.     public static void i(Object obj) { 
  4.         System.out.println(obj); 
  5.     } 
  6.     public static void e(Object e) { 
  7.         System.err.println(e); 
  8.     } 

SeekServer:

服務器端的入口,請求的封裝和接收都在此類,端口暫時寫死在了代碼里,mSelector.select(TIME_OUT) > 0 目的是為了當服務器空閑的時候(沒有任何讀寫甚至請求斷開事件),循環時有個間隔時間,不然基本上相當于while(true){//nothing}了,你懂的。

  1. public class SeekServer extends Thread{ 
  2.     private final int ACCPET_PORT = 55555
  3.     private final int TIME_OUT = 1000
  4.     private Selector mSelector = null
  5.     private ServerSocketChannel mSocketChannel = null
  6.     private ServerSocket mServerSocket = null
  7.     private InetSocketAddress mAddress = null
  8.      
  9.     public SeekServer() { 
  10.         long sign = System.currentTimeMillis(); 
  11.         try { 
  12.             mSocketChannel = ServerSocketChannel.open(); 
  13.             if(mSocketChannel == null) { 
  14.                 System.out.println("can't open server socket channel"); 
  15.             } 
  16.             mServerSocket = mSocketChannel.socket(); 
  17.             mAddress = new InetSocketAddress(ACCPET_PORT); 
  18.             mServerSocket.bind(mAddress); 
  19.             Log.i("server bind port is " + ACCPET_PORT); 
  20.             mSelector = Selector.open(); 
  21.             mSocketChannel.configureBlocking(false); 
  22.             SelectionKey key = mSocketChannel.register(mSelector, SelectionKey.OP_ACCEPT); 
  23.             key.attach(new Acceptor()); 
  24.              
  25.             //檢測Session狀態 
  26.             Looper.getInstance().loop(); 
  27.              
  28.             //開始處理Session 
  29.             SessionProcessor.start(); 
  30.              
  31.             Log.i("Seek server startup in " + (System.currentTimeMillis() - sign) + "ms!"); 
  32.         } catch (ClosedChannelException e) { 
  33.             Log.e(e.getMessage()); 
  34.         } catch (IOException e) { 
  35.             Log.e(e.getMessage()); 
  36.         }  
  37.     } 
  38.      
  39.     public void run() { 
  40.         Log.i("server is listening..."); 
  41.         while(!Thread.interrupted()) { 
  42.             try { 
  43.                 if(mSelector.select(TIME_OUT) > 0) { 
  44.                     Set<SelectionKey> keys = mSelector.selectedKeys(); 
  45.                     Iterator<SelectionKey> iterator = keys.iterator(); 
  46.                     SelectionKey key = null
  47.                     while(iterator.hasNext()) { 
  48.                         key = iterator.next(); 
  49.                         Handler at = (Handler) key.attachment(); 
  50.                         if(at != null) { 
  51.                             at.exec(); 
  52.                         } 
  53.                         iterator.remove(); 
  54.                     } 
  55.                 } 
  56.             } catch (IOException e) { 
  57.                 Log.e(e.getMessage()); 
  58.             } 
  59.         } 
  60.     } 
  61.  
  62.     class Acceptor extends Handler{ 
  63.  
  64.         public void exec(){ 
  65.             try { 
  66.                 SocketChannel sc = mSocketChannel.accept(); 
  67.                 new Session(sc, mSelector); 
  68.             } catch (ClosedChannelException e) { 
  69.                 Log.e(e); 
  70.             } catch (IOException e) { 
  71.                 Log.e(e); 
  72.             } 
  73.         } 
  74.     } 

Handler:

只有一個抽象方法exec,Session將會繼承它。

  1. public abstract class Handler { 
  2.      
  3.     public abstract void exec(); 

Session:

封裝了用戶的請求和SelectionKey和SocketChannel,每次接收到新的請求時都重置它的最后活動時間,通過狀態mState=READING or SENDING 去執行消息的接收與發送,當客戶端異常斷開時則從SessionManager清除該會話。

  1. public class Session extends Handler{ 
  2.  
  3.     private SocketChannel mChannel; 
  4.     private SelectionKey  mKey; 
  5.     private ByteBuffer mRreceiveBuffer = ByteBuffer.allocate(10240);   
  6.     private Charset charset = Charset.forName("UTF-8"); 
  7.     private CharsetDecoder mDecoder = charset.newDecoder(); 
  8.     private CharsetEncoder mEncoder = charset.newEncoder(); 
  9.     private long lastPant;//最后活動時間 
  10.     private final int TIME_OUT = 1000 * 60 * 5//Session超時時間 
  11.     private String key; 
  12.      
  13.     private String sendData = ""
  14.     private String receiveData = null
  15.      
  16.     public static final int READING = 0,SENDING = 1
  17.     int mState = READING; 
  18.      
  19.     public Session(SocketChannel socket, Selector selector) throws IOException { 
  20.         this.mChannel = socket; 
  21.         mChannel = socket; 
  22.         mChannel.configureBlocking(false); 
  23.         mKey = mChannel.register(selector, 0); 
  24.         mKey.attach(this); 
  25.         mKey.interestOps(SelectionKey.OP_READ); 
  26.         selector.wakeup(); 
  27.         lastPant = Calendar.getInstance().getTimeInMillis(); 
  28.     } 
  29.      
  30.     public String getReceiveData() { 
  31.         return receiveData; 
  32.     } 
  33.      
  34.     public void clear() { 
  35.         receiveData = null
  36.     } 
  37.  
  38.     public void setSendData(String sendData) { 
  39.         mState = SENDING; 
  40.         mKey.interestOps(SelectionKey.OP_WRITE); 
  41.         this.sendData = sendData + "\n"
  42.     } 
  43.  
  44.     public boolean isKeekAlive() { 
  45.         return lastPant + TIME_OUT > Calendar.getInstance().getTimeInMillis(); 
  46.     } 
  47.      
  48.     public void setAlive() { 
  49.         lastPant = Calendar.getInstance().getTimeInMillis(); 
  50.     } 
  51.      
  52.     /** 
  53.      * 注銷當前Session 
  54.      */ 
  55.     public void distroy() { 
  56.         try { 
  57.             mChannel.close(); 
  58.             mKey.cancel(); 
  59.         } catch (IOException e) {} 
  60.     } 
  61.      
  62.     @Override 
  63.     public synchronized void exec() { 
  64.         try { 
  65.             if(mState == READING) { 
  66.                 read(); 
  67.             }else if(mState == SENDING) { 
  68.                 write(); 
  69.             } 
  70.         } catch (IOException e) { 
  71.             SessionManager.remove(key); 
  72.             try { 
  73.                 mChannel.close(); 
  74.             } catch (IOException e1) { 
  75.                 Log.e(e1); 
  76.             } 
  77.             mKey.cancel(); 
  78.         } 
  79.     } 
  80.      
  81.     public void read() throws IOException{ 
  82.         mRreceiveBuffer.clear(); 
  83.         int sign = mChannel.read(mRreceiveBuffer); 
  84.         if(sign == -1) { //客戶端連接關閉 
  85.             mChannel.close(); 
  86.             mKey.cancel(); 
  87.         } 
  88.         if(sign > 0) { 
  89.             mRreceiveBuffer.flip(); 
  90.             receiveData = mDecoder.decode(mRreceiveBuffer).toString(); 
  91.             setAlive(); 
  92.             setSign(); 
  93.             SessionManager.addSession(key, this); 
  94.         } 
  95.     } 
  96.      
  97.     private void setSign() { 
  98.         //設置當前Session的Key 
  99.         key = JsonParser.get(receiveData,"imei"); 
  100.         //檢測消息類型是否為心跳包 
  101. //        String type = jo.getString("type"); 
  102. //        if(type.equals("HEART_BEAT")) { 
  103. //            setAlive(); 
  104. //        } 
  105.     } 
  106.      
  107.      
  108.     /** 
  109.      * 寫消息 
  110.      */ 
  111.     public void write() { 
  112.         try { 
  113.             mChannel.write(mEncoder.encode(CharBuffer.wrap(sendData))); 
  114.             sendData = null
  115.             mState = READING; 
  116.             mKey.interestOps(SelectionKey.OP_READ); 
  117.         } catch (CharacterCodingException e) { 
  118.             e.printStackTrace(); 
  119.         } catch (IOException e) { 
  120.             try { 
  121.                 mChannel.close(); 
  122.             } catch (IOException e1) { 
  123.                 Log.e(e1); 
  124.             } 
  125.         } 
  126.     } 

SessionManager:

將所有Session存放到ConcurrentHashMap,這里使用手機用戶的imei做key,ConcurrentHashMap因為是線程安全的,所以能很大程度上避免自己去實現同步的過程,
封裝了一些操作Session的方法例如get,remove等。

  1. public class SessionManager { 
  2.  
  3.     private static ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<String, Session>(); 
  4.      
  5.     public static void addSession(String key,Session session) { 
  6.         sessions.put(key, session); 
  7.     } 
  8.     
  9.     public static Session getSession(String key) { 
  10.         return sessions.get(key); 
  11.     } 
  12.      
  13.     public static Set<String> getSessionKeys() { 
  14.         return sessions.keySet(); 
  15.     } 
  16.      
  17.     public static int getSessionCount() { 
  18.         return sessions.size(); 
  19.     } 
  20.      
  21.     public static void remove(String[] keys) { 
  22.         for(String key:keys) { 
  23.             if(sessions.containsKey(key)) { 
  24.                 sessions.get(key).distroy(); 
  25.                 sessions.remove(key); 
  26.             } 
  27.         } 
  28.     } 
  29.     public static void remove(String key) { 
  30.         if(sessions.containsKey(key)) { 
  31.             sessions.get(key).distroy(); 
  32.             sessions.remove(key); 
  33.         } 
  34.     } 

SessionProcessor

里面使用了JDK自帶的線程池,用來分發處理所有Session中當前需要處理的請求(線程池的初始化參數不是太熟,望有了解的童鞋能告訴我),內部類Process則是將Session再次封裝成SocketRequest和SocketResponse(看到這里是不是有點熟悉的感覺,對沒錯,JavaWeb里到處都是request和response)。

  1. public class SessionProcessor implements Runnable{ 
  2.      
  3.     private static Runnable processor = new SessionProcessor(); 
  4.     private static ThreadPoolExecutor pool = new ThreadPoolExecutor(10200500, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),new ThreadPoolExecutor.CallerRunsPolicy()); 
  5.     public static void start() { 
  6.         new Thread(processor).start(); 
  7.     } 
  8.      
  9.     @Override 
  10.     public void run() { 
  11.         while(true) { 
  12.             Session tmp = null
  13.             for(String key:SessionManager.getSessionKeys()) { 
  14.                 tmp = SessionManager.getSession(key); 
  15.                 //處理Session未處理的請求 
  16.                 if(tmp.getReceiveData() != null) { 
  17.                     pool.execute(new Process(tmp)); 
  18.                 } 
  19.             } 
  20.             try { 
  21.                 Thread.sleep(10); 
  22.             } catch (InterruptedException e) { 
  23.                 Log.e(e); 
  24.             } 
  25.         } 
  26.     } 
  27.      
  28.     class Process implements Runnable { 
  29.  
  30.         private SocketRequest request; 
  31.         private SocketResponse response; 
  32.          
  33.         public Process(Session session) { 
  34.             //將Session封裝成Request和Response 
  35.             request = new SocketRequest(session); 
  36.             response = new SocketResponse(session); 
  37.         } 
  38.          
  39.         @Override 
  40.         public void run() { 
  41.             new RequestTransform().transfer(request, response); 
  42.         } 
  43.     } 
  44.  

RequestTransform里的transfer方法利用反射對請求參數中的請求類別和請求動作來調用不同類的不同方法(UserHandler和MessageHandler)

  1. public class RequestTransform { 
  2.  
  3.     public void transfer(SocketRequest request,SocketResponse response) { 
  4.         String action = request.getValue("action"); 
  5.         String handlerName = request.getValue("handler"); 
  6.         //根據Session的請求類型,讓不同的類方法去處理 
  7.         try { 
  8.             Class<?> c= Class.forName("com.seek.server.handler." + handlerName); 
  9.             Class<?>[] arg=new Class[]{SocketRequest.class,SocketResponse.class}; 
  10.             Method method=c.getMethod(action,arg); 
  11.             method.invoke(c.newInstance(), new Object[]{request,response}); 
  12.         } catch (Exception e) { 
  13.             e.printStackTrace(); 
  14.         } 
  15.     } 

SocketRequest和SocketResponse

  1. public class SocketRequest { 
  2.  
  3.     private Session mSession; 
  4.     private String  mReceive; 
  5.      
  6.     public SocketRequest(Session session) { 
  7.         mSession = session; 
  8.         mReceive = session.getReceiveData(); 
  9.         mSession.clear(); 
  10.     } 
  11.      
  12.     public String getValue(String key) { 
  13.         return JsonParser.get(mReceive, key); 
  14.     } 
  15.      
  16.     public String getQueryString() { 
  17.         return mReceive; 
  18.     } 
  1. public class SocketResponse {  
  2.   
  3.     private Session mSession;  
  4.     public SocketResponse(Session session) {  
  5.         mSession = session;  
  6.     }  
  7.       
  8.     public void write(String msg) {  
  9.         mSession.setSendData(msg);  
  10.     }  
  11. }  

最后則是兩個處理請求的Handler

  1. public class UserHandler { 
  2.  
  3.     public void login(SocketRequest request,SocketResponse response) { 
  4.         System.out.println(request.getQueryString()); 
  5.         //TODO: 處理用戶登錄 
  6.         response.write("你肯定收到消息了"); 
  7.     } 
  1. public class MessageHandler { 
  2.     public void send(SocketRequest request,SocketResponse response) { 
  3.         System.out.println(request.getQueryString()); 
  4.         //消息發送 
  5.         String key = request.getValue("imei"); 
  6.         Session session = SessionManager.getSession(key); 
  7.         new SocketResponse(session).write(request.getValue("sms")); 
  8.     } 

還有個監測是否超時的類Looper,定期去刪除Session

  1. public class Looper extends Thread{ 
  2.     private static Looper looper = new Looper(); 
  3.     private static boolean isStart = false
  4.     private final int INTERVAL = 1000 * 60 * 5
  5.     private Looper(){} 
  6.     public static Looper getInstance() { 
  7.         return looper; 
  8.     } 
  9.      
  10.     public void loop() { 
  11.         if(!isStart) { 
  12.             isStart = true
  13.             this.start(); 
  14.         } 
  15.     } 
  16.      
  17.     public void run() { 
  18.         Task task = new Task(); 
  19.         while(true) { 
  20.             //Session過期檢測 
  21.             task.checkState(); 
  22.             //心跳包檢測 
  23.             //task.sendAck(); 
  24.             try { 
  25.                 Thread.sleep(INTERVAL); 
  26.             } catch (InterruptedException e) { 
  27.                 Log.e(e); 
  28.             } 
  29.         } 
  30.     } 
  1. public class Task { 
  2.     public void checkState() { 
  3.         Set<String> keys = SessionManager.getSessionKeys(); 
  4.         if(keys.size() == 0) { 
  5.             return
  6.         } 
  7.         List<String> removes = new ArrayList<String>(); 
  8.         Iterator<String> iterator = keys.iterator(); 
  9.         String key = null
  10.         while(iterator.hasNext()) { 
  11.             key = iterator.next(); 
  12.             if(!SessionManager.getSession(key).isKeekAlive()) { 
  13.                 removes.add(key); 
  14.             } 
  15.        } 
  16.         if(removes.size() > 0) { 
  17.             Log.i("sessions is time out,remove " + removes.size() + "session"); 
  18.         } 
  19.         SessionManager.remove(removes.toArray(new String[removes.size()])); 
  20.     } 
  21.      
  22.     public void sendAck() { 
  23.         Set<String> keys = SessionManager.getSessionKeys(); 
  24.         if(keys.size() == 0) { 
  25.             return
  26.         } 
  27.         Iterator<String> iterator = keys.iterator(); 
  28.         while(iterator.hasNext()) { 
  29.             iterator.next(); 
  30.             //TODO 發送心跳包 
  31.         } 
  32.     } 

注意,在Task和SessionProcessor類里都有對SessionManager的sessions做遍歷,文中使用的方法并不是很好,主要是效率問題,推薦使用遍歷Entry的方式來獲取Key和Value,因為一直在JavaWeb上折騰,所以會的童鞋看到Request和Response會挺親切,這個例子沒有經過任何安全和性能測試,如果需要放到生產環境上得話請先自行做測試- -!

客戶端請求時的數據內容例如{handler:"UserHandler",action:"login",imei:"2364656512636".......},這些約定就自己來定了。

原文鏈接:http://www.cnblogs.com/freedom-elf/archive/2011/08/11/2135015.html

【編輯推薦】

  1. Java解讀NIO Socket非阻塞模式
  2. 利用NIO建立Socket服務器
  3. Java NIO的wakeup剖析
  4. Java NIO類庫關系圖解
  5. 淺析Tomcat NIO 配置
責任編輯:林師授 來源: 黎某人的博客
相關推薦

2011-12-08 13:04:06

JavaNIO

2011-12-08 10:12:34

JavaNIO

2011-03-11 09:51:47

Java NIO

2011-12-07 17:05:45

JavaNIO

2009-08-18 12:51:19

服務器+客戶端

2011-12-15 11:11:51

JavaNIO

2011-06-07 08:03:30

2019-11-17 22:31:18

TCP連接流量Java

2011-12-15 10:19:55

JavaNIO

2009-12-14 10:44:51

Java 7NIO2

2009-04-26 22:27:54

觸發器密碼修改數據庫

2018-01-15 09:32:59

即時通信服務器架構

2019-01-27 20:00:14

Linux靜態文件服務器

2011-02-22 10:01:13

2010-03-19 14:01:55

Java Socket

2019-04-26 10:57:26

無服務器應用程序HTTP

2017-03-13 14:02:10

分布式聊天服務器

2011-10-21 09:45:20

zEnterprise大型機服務器

2011-11-04 16:50:33

UbuntuARM服務器

2009-06-11 09:20:15

GlassFish是什OSGi
點贊
收藏

51CTO技術棧公眾號

在线观看国产网站| 日韩伦理一区二区三区av在线| 欧洲性xxxx| 伊人久久大香| 亚洲在线视频免费观看| 久久免费一区| 在线观看中文字幕2021| 在线电影一区二区| 亚洲精品国产欧美| 在线观看免费污视频| 欧美日韩色网| 久久色在线观看| 成人中文字幕在线观看| 欧美亚洲精品天堂| 99视频精品视频高清免费| 亚洲精品98久久久久久中文字幕| 欧美一级特黄a| 99在线视频影院| 日本一区二区高清| 精品伦精品一区二区三区视频| 在线观看中文字幕码| 日韩一级欧洲| 欧美xxxx综合视频| 免费成人深夜天涯网站| 美国成人xxx| 欧美浪妇xxxx高跟鞋交| 免费一级特黄毛片| 快射视频在线观看| 国产欧美视频一区二区| 精品久久一区二区三区蜜桃| 999免费视频| 日本女优在线视频一区二区| 欧美性受xxxx白人性爽| 精品爆乳一区二区三区无码av| 国产一区二区三区四区五区| 亚洲国产高潮在线观看| 伊人成人免费视频| av在线一区不卡| 伊人久久大香线蕉综合热线| 亚洲最新av在线网站| 久久人人爽人人爽人人片| 国产精品xxxxx| 毛片在线免费视频| 在线看片欧美| 欧美国产在线电影| 加勒比av在线播放| 午夜视频精品| 欧美日韩aaaa| 九九精品在线观看视频 | 狠狠色综合网站久久久久久久| 超碰在线免费97| 日韩成人伦理电影在线观看| 国产成人a亚洲精品| 国产成人精品网| 久久精品91| 欧洲美女7788成人免费视频| 五月激情六月丁香| 久久久久久网| 国产精品99一区| 亚洲中文无码av在线| 日本不卡高清视频| 国产精品专区第二| 97精品人妻一区二区三区香蕉| 免费精品99久久国产综合精品| 国产精品久久网| 亚洲天堂网在线视频| 韩国成人精品a∨在线观看| 国产一区二区在线免费| 国产伦精品一区二区三区四区| 久久黄色级2电影| 亚洲伊人第一页| 黄色三级网站在线观看| 99久久久精品| 区一区二区三区中文字幕| av网在线观看| 成人免费在线视频| 男人的天堂avav| 国产福利在线免费观看| 欧美日韩综合视频| 在线免费视频一区| 看亚洲a级一级毛片| 精品国产免费人成在线观看| 美女又爽又黄免费| 精品久久中文| 欧美裸体xxxx极品少妇| 日本少妇xxxx动漫| 免费在线欧美黄色| 成人av.网址在线网站| www.五月婷婷| 久久久久久久久99精品| 婷婷视频在线播放| yellow在线观看网址| 欧日韩精品视频| 亚洲精品久久久久久| a看欧美黄色女同性恋| 亚洲女人天堂av| 国产三级国产精品国产国在线观看| 欧美日韩一区自拍| 国产99久久精品一区二区 夜夜躁日日躁 | 亚洲v在线看| 国内揄拍国内精品| 亚洲性猛交富婆| 成人免费视频播放| 亚洲福利av在线| 国产白浆在线免费观看| 欧美精品乱码久久久久久| 国产美女视频免费观看下载软件| 99视频精品全国免费| 欧美一级淫片丝袜脚交| 99久久精品国产一区色| 久久日韩粉嫩一区二区三区| 日韩精品手机在线观看| 韩国精品主播一区二区在线观看 | 亚洲高清自拍| 91精品国产自产在线老师啪| 深夜福利在线观看直播| 一区二区三区欧美在线观看| 91视频免费版污| 精品欧美午夜寂寞影院| 欧美大成色www永久网站婷| 最近免费中文字幕大全免费版视频| 国产激情偷乱视频一区二区三区| 日韩av不卡在线播放| 嗯啊主人调教在线播放视频| 日韩欧美一区二区视频| 特黄一区二区三区| 天堂av在线一区| 精品视频一区在线| 日本片在线观看| 日韩一区二区免费电影| 日韩一区二区三区四区视频| 美女精品网站| 免费精品视频一区| 欧美久久天堂| 日韩av在线免费播放| 精品无码人妻一区二区三区| 国产在线视频一区二区三区| 亚洲一区二区高清视频| 欧洲av一区二区| 亚洲欧美制服综合另类| 日韩欧美国产亚洲| 成人精品免费看| 久久这里只有精品18| 日韩精品一区二区三区免费视频| 精品国产一区av| 91成品人影院| 亚洲视频一区二区在线观看| 色91精品久久久久久久久| 97欧美在线视频| 国产美女91呻吟求| 里番在线观看网站| 337p亚洲精品色噜噜| 污软件在线观看| 国产精品影音先锋| 污污污污污污www网站免费| 日韩高清在线观看一区二区| 九九热这里只有精品免费看| 国产黄色免费大片| 亚洲国产日韩综合久久精品| 小毛片在线观看| 久久精品观看| 亚洲国产精品久久久久婷婷老年| 欧美成人app| 久久综合亚洲社区| 亚洲a视频在线| 黑人精品xxx一区一二区| 女尊高h男高潮呻吟| 蜜臀av一区二区三区| 波多野结衣三级在线| 国产在线视频欧美一区| 欧美极品在线播放| 色就是色亚洲色图| 欧美曰成人黄网| 91高清免费看| 成人小视频在线观看| 熟女性饥渴一区二区三区| 国产精品一区高清| 成人看片人aa| 成人国产电影在线观看| 一本色道久久综合狠狠躁篇的优点| 国产日韩在线免费观看| 亚洲欧美日韩成人高清在线一区| 免费黄色av网址| 国产精品s色| 91精品国产高清久久久久久91裸体| 黑人另类精品××××性爽| 亚洲欧美日韩另类| 国产婷婷一区二区三区久久| 午夜精品久久久久久久99樱桃| 手机看片日韩av| 国产成人精品亚洲午夜麻豆| 亚洲乱码中文字幕久久孕妇黑人| 99久久综合| 裸体丰满少妇做受久久99精品| 亚洲国产91视频| 高清一区二区三区日本久| 成人影院免费观看| 精品久久久久久无| 国模私拍一区二区| 亚洲成人777| 成人18视频免费69| 99热在这里有精品免费| 中文字幕66页| 一区二区毛片| 成人黄色片免费| 成人影院在线| 久久精品aaaaaa毛片| 国产精品99久久免费| 欧美主播福利视频| 久草免费在线色站| 日韩中文理论片| 人人九九精品| 精品国产乱子伦一区| 一区二区视频免费观看| 欧美性猛交xxxx免费看漫画 | 日韩欧美一区视频| 久操视频免费在线观看| 国产精品视频一二| 中文字幕丰满孑伦无码专区| 成人免费观看视频| 天堂网成人在线| 乱一区二区av| 另类小说色综合| 久热精品在线| 欧美牲交a欧美牲交aⅴ免费真 | 精品人妻一区二区三区四区不卡 | av中文字幕在线观看| 伊人久久久久久久久久久久久| 五十路在线观看| 精品国产91洋老外米糕| 精品久久久久久亚洲综合网站| 欧美在线free| 亚洲国产无线乱码在线观看| 日韩欧美一区二区三区久久| 精品国产免费观看| 亚洲国产日韩综合久久精品| 国产在线视频你懂的| 一区二区三区国产豹纹内裤在线| 午夜精品福利在线视频| 国产精品国产三级国产a| 免费观看a级片| 欧美韩国一区二区| 五月天精品视频| 国产色综合久久| www.黄色在线| 国产精品无人区| 国产精品麻豆一区| 中文字幕综合网| 中文字幕电影av| 亚洲一区二区三区四区中文字幕| 久艹视频在线观看| 亚洲不卡一区二区三区| 日本一级淫片色费放| 婷婷夜色潮精品综合在线| 国产成人精品一区二三区| 欧美日韩免费在线观看| 久久久黄色大片| 欧美影院午夜播放| 亚洲自拍偷拍另类| 日韩一区二区三区电影| 全部免费毛片在线播放一个| 日韩av在线免费观看一区| 免费av在线电影| 中日韩美女免费视频网站在线观看| 91社区在线| 精品少妇v888av| 少妇视频在线观看| 国产精品99蜜臀久久不卡二区| 日本免费在线一区| 成人网页在线免费观看| 99re8这里有精品热视频8在线| 国精产品一区二区| japanese国产精品| 男人草女人视频| 小嫩嫩精品导航| 亚洲免费av一区| 成人av免费在线观看| av黄色在线免费观看| 亚洲天堂2016| 精品欧美一区二区三区免费观看| 欧美亚洲高清一区| 成人1区2区3区| 亚洲视频国产视频| 久久综合网导航| 91tv亚洲精品香蕉国产一区7ujn| 国产精品字幕| 国产精品久久久久久久久婷婷 | aa级大片欧美| 91视频免费看片| 午夜精品在线看| 一二三区在线播放| 亚洲国产欧美自拍| av大片在线观看| 韩日欧美一区二区| 亚洲精品一区av| 蜜桃999成人看片在线观看| 亚洲精品极品少妇16p| 男人日女人bb视频| 国产乱人伦精品一区二区在线观看| 性久久久久久久久久| 亚洲免费色视频| 亚洲精品毛片一区二区三区| 精品国产一区二区三区久久久蜜月 | 色综合av综合无码综合网站| 国产一区在线精品| 国产高潮呻吟久久| 亚洲成人av一区二区| 国产乱色精品成人免费视频| 亚洲色无码播放| mm视频在线视频| 成人写真视频福利网| 精品久久久中文字幕| 免费成人午夜视频| 国产精品中文字幕欧美| 日本成人精品视频| 欧美综合久久久| 亚洲色图21p| 欧美极品在线视频| 日本精品视频| 在线视频福利一区| 日韩精品乱码免费| 午夜一区二区三区免费| 亚洲综合久久久| av中文字幕免费在线观看| 中文字幕一区电影| 亚洲伦乱视频| 欧洲在线视频一区| 国产精品毛片在线| 久久久久亚洲AV成人无码国产| 亚洲综合色区另类av| 99久久99久久久精品棕色圆| 色多多国产成人永久免费网站| 欧美一区 二区 三区| 欧美少妇一区| 美女国产一区| 一区二区精品免费| 欧美视频一二三| 三级在线观看| 青青草99啪国产免费| 欧美自拍视频| 六月丁香婷婷激情| xf在线a精品一区二区视频网站| 日韩免费黄色片| 亚洲精品国产欧美| 中文字幕资源网在线观看免费| 久久国产精品99久久久久久丝袜| 亚洲精品专区| 不卡一区二区在线观看| 欧美性猛交xxxx久久久| 国产小视频免费在线观看| 国产精品久久久久7777婷婷| 欧美色网址大全| 五月天婷婷亚洲| 亚洲你懂的在线视频| 亚洲成a人片77777精品| 欧美大片在线看| 国内精品国产成人国产三级粉色| 国产亚洲黄色片| wwwwww.欧美系列| 免费黄色片视频| y97精品国产97久久久久久| 91精品网站在线观看| 97av中文字幕| 99精品视频中文字幕| 无码视频在线观看| 日韩亚洲精品视频| 在线精品国产亚洲| 久久精品免费一区二区| 国产精品少妇自拍| 国产三级伦理片| 国内精品一区二区三区四区| 丝袜连裤袜欧美激情日韩| 可以免费在线看黄的网站| 国产精品伦理一区二区| www.激情五月| 日本高清不卡在线| 亚洲成人国产| 91精品人妻一区二区| 欧美日韩一区 二区 三区 久久精品| 成人免费看片| 裸模一区二区三区免费| 精品一区二区三区免费| 日本三级中文字幕| 色琪琪综合男人的天堂aⅴ视频| 人人爱人人干婷婷丁香亚洲| 日本黄网站免费| 亚洲欧美另类久久久精品| 色呦呦中文字幕| 国产欧亚日韩视频| 亚洲区国产区| 女同久久另类69精品国产| 亚洲国产精品久久久| 精品久久福利| 国产av麻豆mag剧集| 中文字幕一区二区三| 五月天激情婷婷| 亚洲精品女av网站| 日韩不卡一区二区三区| 国产一级大片在线观看| 综合av色偷偷网|