精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

欧美黑人视频一区| 久久精品欧美日韩| 久久99青青精品免费观看| 久久久国产精品久久久| av爱爱亚洲一区| 亚洲精品成人网| 免费看a级黄色片| 国产淫片在线观看| 最近更新的2019中文字幕| 久久精品人人做人人爽电影| www.com国产| 欧美1级片网站| 精品国产免费人成电影在线观看四季 | 手机看片久久久| 日韩国产欧美一区二区| 久久精品视频9| 天天综合网站| 一区二区三区美女视频| 欧美日韩在线播放一区二区| 99久久精品国产成人一区二区| 国产精品综合| 欧美日韩国产成人在线| 99久久99久久精品免费| 国产精品xxxav免费视频| 欧美日韩亚洲综合在线 | 欧美日韩国产另类不卡| 欧美日韩xxx| 91亚色免费| 国产一卡二卡三卡| 国产精品99免费看| 久久精品国产欧美亚洲人人爽| 国产黄色三级网站| 亚洲天堂av资源在线观看| 欧美性受xxxx黑人xyx| 国产中文字幕视频在线观看| 成年人网站在线| 中文在线免费一区三区高中清不卡 | 国产午夜福利片| 欧美xxx在线观看| 色先锋资源久久综合5566| 深爱五月激情网| 国产suv精品一区| 91精品国产全国免费观看| 亚洲国产成人va在线观看麻豆| 欧美日韩美女| 欧美午夜激情小视频| 国产美女主播在线| 亚洲va韩国va欧美va精品| 国产精品偷伦一区二区 | 黄色在线播放| 91精品久久久久久蜜桃| 人成免费在线视频| 私拍精品福利视频在线一区| 精品国产3级a| 精彩视频一区二区| 视频直播国产精品| 日本猛少妇色xxxxx免费网站| 亚洲素人在线| 亚洲图片欧美午夜| 精品人伦一区二区| 欧美久久综合网| 在线观看国产精品日韩av| 在线播放国产一区中文字幕剧情欧美 | 美女亚洲一区| 日韩精品在线观| 全黄一级裸体片| 精品国产91乱码一区二区三区四区 | 日本乱码高清不卡字幕| 成人精品小视频| 美女色狠狠久久| 欧美精品高清视频| 精品人妻一区二区三区免费| 91九色鹿精品国产综合久久香蕉| 日韩精品一区在线观看| 亚洲欧美高清在线| 伊人久久大香线蕉| 最近中文字幕日韩精品 | 中文在线观看免费| 亚洲一区二区美女| 日本免费不卡一区二区| 日本一道高清亚洲日美韩| 欧美日韩一级大片网址| 国产老头和老头xxxx×| 精品无人区一区二区| 亚洲免费视频在线观看| 天堂av免费在线| 欧美婷婷在线| 日本视频久久久| 国产伦精品一区二区三区视频痴汉 | 午夜在线视频播放| 一区二区在线电影| 人妻少妇被粗大爽9797pw| 2019日韩中文字幕mv| 丰满熟妇人妻中文字幕| 久久精品视频一区二区| 在线观看成人免费| 在线看的毛片| 欧美男男青年gay1069videost| 俄罗斯黄色录像| 成人在线电影在线观看视频| 欧美激情久久久久久| 天天综合网久久综合网| 欧美一区=区| 亚洲一区中文字幕| 国产毛片在线| 亚洲一级片在线观看| 亚洲欧美激情网| 国产精品极品在线观看| 俺去亚洲欧洲欧美日韩| 中文字幕在线观看视频网站| 紧缚捆绑精品一区二区| 久久精品99| 性网站在线观看| 欧美三区在线观看| 97人妻天天摸天天爽天天| 91精品国产91久久久久久黑人| 欧美在线国产精品| 亚洲爱情岛论坛永久| 国产精品免费免费| 男人揉女人奶房视频60分| 国产精品一区二区三区四区在线观看 | 99视频精品免费| 日韩激情欧美| 日韩中文视频免费在线观看| 伊人手机在线视频| 国产999精品久久久久久绿帽| 亚洲图色在线| 精品亚洲美女网站| 日韩av在线免费观看| 神马午夜精品91| 美洲天堂一区二卡三卡四卡视频| 久久精品日产第一区二区三区精品版 | 亚洲精品一二三**| 北条麻妃久久精品| 国产情侣免费视频| 久久精品亚洲国产奇米99| 久激情内射婷内射蜜桃| 中文无码日韩欧| 九九九久久久久久| 99re只有精品| 亚洲欧美怡红院| 成 人 黄 色 小说网站 s色| 不卡视频在线| 国产精品美女视频网站| 蜜桃91精品入口| www日韩tube| 91黄色在线观看| 国产精品成人一区二区三区电影毛片| 国产九九热视频| 国产电影一区二区| 久久手机精品视频| 96亚洲精品久久久蜜桃| 国产精品久久久久婷婷| 日韩精品你懂的| 国产精品久久久久一区二区三区厕所| 国产剧情久久久久久| 日本中文字幕电影在线免费观看 | 国产精品免费看片| 五月天中文字幕在线| 午夜精品一区二区三区国产| 国产日韩中文字幕| 91黄色在线| 精品国产精品网麻豆系列| 日韩免费一级片| 久久亚洲精品国产精品紫薇| 日韩av手机版| 在线精品国产| 激情五月综合色婷婷一区二区 | 欧美午夜寂寞影院| 国产小视频你懂的| 国产aⅴ精品一区二区三区色成熟| av在线免费观看国产| 日本妇女一区| 国产精品免费视频xxxx| 九色porny在线| 精品88久久久久88久久久| 日本道在线观看| 欧美激情一区二区三区全黄 | 蜜桃精品一区二区三区| 精品中文字幕在线2019| 婷婷丁香花五月天| 欧美日韩一区久久| 久久久久久久9999| wwww国产精品欧美| 三区视频在线观看| 亚洲另类黄色| 一区二区在线观看网站| 18国产精品| 日本一区二区三区四区视频| a级网站在线播放| 日韩精品在线观看一区| 一级全黄少妇性色生活片| 亚洲一区二区三区国产| 亚洲一区二区自偷自拍 | 最新日本在线观看| 亚洲国产欧美日韩精品| 在线观看亚洲一区二区| 性久久久久久久久久久久| 欧美波霸videosex极品| 国产黄色精品网站| 好男人www社区| 樱桃成人精品视频在线播放| 性欧美精品一区二区三区在线播放| 日韩精品一级| 国产精品欧美风情| 91破解版在线观看| 久久精品国产v日韩v亚洲| 日本福利片高清在线观看| 91精品久久久久久久99蜜桃| 国产又黄又爽又色| 玉足女爽爽91| 黄色av片三级三级三级免费看| a在线播放不卡| 51自拍视频在线观看| 日本亚洲三级在线| 黄色免费视频大全| 亚洲午夜91| 中文字幕精品在线播放| 日韩免费av| 日韩视频在线观看国产| 女仆av观看一区| 动漫美女被爆操久久久| 91精品国产一区二区在线观看| 国产成人黄色av| 天堂а√在线最新版中文在线| 欧美黄色性视频| 在线不卡日本v二区707| 久久精品国产清自在天天线| 番号在线播放| 亚洲色图第一页| 亚洲欧洲精品视频| 亚洲精品一区在线观看| 国产av无码专区亚洲a∨毛片| 欧美日韩在线电影| 中文亚洲av片在线观看| 在线这里只有精品| 99re视频| 午夜影视一区二区三区| 久久久久久久一| 国产色婷婷在线| 欧美激情精品久久久久久大尺度| 超碰最新在线| 久久视频免费在线播放| 欧美r级在线| yellow中文字幕久久| 免费日本一区二区三区视频| 日韩在线视频观看正片免费网站| 高清日韩av电影| 一区二区福利视频| 137大胆人体在线观看| 永久555www成人免费| se在线电影| 日日狠狠久久偷偷四色综合免费| 在线免费看黄网站| www.久久久久| 亚洲一区在线观看免费| 欧美一区二区视频在线| 日韩电影不卡一区| 国产在线一区二区三区四区| 99re热精品视频| 国产精品久久久久久久小唯西川| 北条麻妃一区二区三区在线观看| 懂色中文一区二区三区在线视频| av毛片精品| 久久99精品久久久久久久久久| 亚洲v天堂v手机在线| 日本高清不卡一区二区三| 精品国产一区二区三区小蝌蚪 | 日韩亚洲在线视频| 尤物精品在线| 亚洲国产精品久久久久爰色欲| 久久久久久一区二区| 九九九在线观看视频| 国产在线精品一区二区三区不卡| 波多野结衣三级视频| 99视频精品全部免费在线| 女尊高h男高潮呻吟| 亚洲国产成人一区二区三区| 日本在线一级片| 五月综合激情婷婷六月色窝| 精品免费囯产一区二区三区 | 欧美男男gaytwinkfreevideos| 色女孩综合网| 欧美日韩亚洲一区二区三区在线| 国产午夜大地久久| 美女网站色91| 人妻 丝袜美腿 中文字幕| 久久久久久久综合日本| 黑人操日本美女| 性欧美大战久久久久久久久| 中文字幕精品一区二区精| 日韩精品一区二区三区在线观看 | 久久gogo国模啪啪裸体| 国产伦理一区二区三区| 成人看的视频| www插插插无码视频网站| 青青草国产精品亚洲专区无| 91成人在线观看喷潮蘑菇| 国产日韩精品一区二区三区在线| 久久99久久98精品免观看软件| 色中色一区二区| 亚洲爆乳无码一区二区三区| 中文字幕av一区中文字幕天堂| 91色在线看| 3d动漫啪啪精品一区二区免费 | 高清一区二区三区| 午夜精品一区二区在线观看| 亚洲看片一区| 日本美女久久久| 国产欧美日韩卡一| 国产午夜福利片| 日韩无一区二区| 97超碰人人在线| 日本中文字幕不卡免费| 国内精品国产成人国产三级粉色 | 激情在线小视频| 国产精品久久一区| 日韩手机在线| 国产人妻777人伦精品hd| 国产一区二区三区在线观看免费 | www日本在线观看| 国产精品久久综合| 国产主播第一页| 日韩精品视频在线播放| wwwwxxxx在线观看| 亚洲字幕在线观看| 亚洲91视频| 中文字幕成人在线视频| 国产日产精品一区| 东京热一区二区三区四区| 亚洲精品999| 好吊日av在线| 国产激情一区二区三区在线观看| 久久精品亚洲人成影院| 9l视频白拍9色9l视频| 国产欧美综合色| 久草热在线观看| 在线播放国产精品| 99久久婷婷国产综合精品首页| 欧美日韩电影一区二区| 亚欧成人精品| 亚洲一级中文字幕| 日本黄色一区二区| 国产午夜视频在线观看| 国产精品69久久久久| 久久99高清| 激情网站五月天| 国产欧美精品国产国产专区| 亚洲大尺度在线观看| 国产午夜精品全部视频播放| 国产麻豆久久| 亚洲午夜精品一区二区| 久草精品在线观看| 顶臀精品视频www| 欧美电影免费观看完整版 | 国产精品黄页免费高清在线观看| 蜜臀av免费一区二区三区| 精品久久久久av| 国产日韩欧美不卡| 国产精品久久久久久免费播放| 久久伊人精品视频| www.神马久久| www.com毛片| 欧美—级在线免费片| 91国内精品久久久| 久国内精品在线| 美女一区二区在线观看| 成年人网站大全| 亚洲人成影院在线观看| 黄色av一区二区三区| 欧美专区在线视频| av伊人久久| 台湾佬美性中文| 午夜精品一区二区三区免费视频 | 欧美成人国产va精品日本一级| 亚洲精品黑牛一区二区三区| www.com毛片| 亚洲视频在线一区二区| 日韩一级在线播放| 国产成人中文字幕| 一区二区电影在线观看| 亚洲av无码一区二区三区观看| 在线观看成人小视频| 99久久精品免费观看国产| 久久精品丝袜高跟鞋| 极品尤物av久久免费看| 中文字幕第15页| 日韩亚洲精品视频| 乱亲女h秽乱长久久久| 激情 小说 亚洲 图片: 伦| 久久最新资源网| 成人影音在线| 日本一区高清在线视频| 九色综合狠狠综合久久| 日韩精品久久久久久久| 最近2019免费中文字幕视频三| av成人资源| 亚洲欧美在线一区二区| 欧美日韩亚洲国产| 少妇久久久久久被弄到高潮|