久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

中间件系列「三」netty之NIO基础

發(fā)布時(shí)間:2024/10/5 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 中间件系列「三」netty之NIO基础 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Java NIO系統(tǒng)的核心在于:通道(Channel)和緩沖區(qū)(Buffer)。通道表示打開到 IO 設(shè)備(例如:文件、套接字)的連接。若需要使用 NIO 系統(tǒng),需要獲取用于連接 IO 設(shè)備的通道以及用于容納數(shù)據(jù)的緩沖區(qū)。然后操作緩沖區(qū),對(duì)數(shù)據(jù)進(jìn)行處理

簡(jiǎn)而言之,通道負(fù)責(zé)傳輸,緩沖區(qū)負(fù)責(zé)存儲(chǔ)

常見的Channel有以下四種,其中FileChannel主要用于文件傳輸,其余三種用于網(wǎng)絡(luò)通信

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

Buffer有以下幾種,其中使用較多的是ByteBuffer

  • ByteBuffer
    • MappedByteBuffer
    • DirectByteBuffer
    • HeapByteBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer
  • CharBuffer

1、Selector

在使用Selector之前,處理socket連接還有以下兩種方法

使用多線程技術(shù)

為每個(gè)連接分別開辟一個(gè)線程,分別去處理對(duì)應(yīng)的socke連接

這種方法存在以下幾個(gè)問題

  • 內(nèi)存占用高
    • 每個(gè)線程都需要占用一定的內(nèi)存,當(dāng)連接較多時(shí),會(huì)開辟大量線程,導(dǎo)致占用大量?jī)?nèi)存
  • 線程上下文切換成本高
  • 只適合連接數(shù)少的場(chǎng)景
    • 連接數(shù)過多,會(huì)導(dǎo)致創(chuàng)建很多線程,從而出現(xiàn)問題

使用線程池技術(shù)

使用線程池,讓線程池中的線程去處理連接

這種方法存在以下幾個(gè)問題

  • 阻塞模式下,線程僅能處理一個(gè)連接
    • 線程池中的線程獲取任務(wù)(task)后,只有當(dāng)其執(zhí)行完任務(wù)之后(斷開連接后),才會(huì)去獲取并執(zhí)行下一個(gè)任務(wù)
    • 若socke連接一直未斷開,則其對(duì)應(yīng)的線程無法處理其他socke連接
  • 僅適合短連接場(chǎng)景
    • 短連接即建立連接發(fā)送請(qǐng)求并響應(yīng)后就立即斷開,使得線程池中的線程可以快速處理其他連接

使用選擇器(這也叫響應(yīng)式編程)

selector 的作用就是配合一個(gè)線程來管理多個(gè) channel(fileChannel因?yàn)槭亲枞降?#xff0c;所以無法使用selector),獲取這些 channel 上發(fā)生的事件,這些 channel 工作在非阻塞模式下,當(dāng)一個(gè)channel中沒有執(zhí)行任務(wù)時(shí),可以去執(zhí)行其他channel中的任務(wù)。適合連接數(shù)多,但流量較少的場(chǎng)景

若事件未就緒,調(diào)用 selector 的 select() 方法會(huì)阻塞線程,直到 channel 發(fā)生了就緒事件。這些事件就緒后,select 方法就會(huì)返回這些事件交給 thread 來處理

2、ByteBuffer

使用方式

  • 向 buffer 寫入數(shù)據(jù),例如調(diào)用 channel.read(buffer)
  • 調(diào)用 flip() 切換至讀模式
    • flip會(huì)使得buffer中的limit變?yōu)閜osition,position變?yōu)?
  • 從 buffer 讀取數(shù)據(jù),例如調(diào)用 buffer.get()
  • 調(diào)用 clear() 或者compact()切換至寫模式
    • 調(diào)用clear()方法時(shí)position=0,limit變?yōu)閏apacity
    • 調(diào)用compact()方法時(shí),會(huì)將緩沖區(qū)中的未讀數(shù)據(jù)壓縮到緩沖區(qū)前面
  • 重復(fù)以上步驟

使用ByteBuffer讀取文件中的內(nèi)容

public class TestByteBuffer {public static void main(String[] args) {// 獲得FileChanneltry (FileChannel channel = new FileInputStream("stu.txt").getChannel()) {// 獲得緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(10);int hasNext = 0;StringBuilder builder = new StringBuilder();while((hasNext = channel.read(buffer)) > 0) {// 切換模式 limit=position, position=0buffer.flip();// 當(dāng)buffer中還有數(shù)據(jù)時(shí),獲取其中的數(shù)據(jù)while(buffer.hasRemaining()) {builder.append((char)buffer.get());}// 切換模式 position=0, limit=capacitybuffer.clear();}System.out.println(builder.toString());} catch (IOException e) {}} }

核心屬性

字節(jié)緩沖區(qū)的父類Buffer中有幾個(gè)核心屬性,如下

// Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity;
  • capacity:緩沖區(qū)的容量。通過構(gòu)造函數(shù)賦予,一旦設(shè)置,無法更改
  • limit:緩沖區(qū)的界限。位于limit 后的數(shù)據(jù)不可讀寫。緩沖區(qū)的限制不能為負(fù),并且不能大于其容量
  • position下一個(gè)讀寫位置的索引(類似PC)。緩沖區(qū)的位置不能為負(fù),并且不能大于limit
  • mark:記錄當(dāng)前position的值。position被改變后,可以通過調(diào)用reset() 方法恢復(fù)到mark的位置。

以上四個(gè)屬性必須滿足以下要求

mark <= position <= limit <= capacity

核心方法

put()方法

  • put()方法可以將一個(gè)數(shù)據(jù)放入到緩沖區(qū)中。
  • 進(jìn)行該操作后,postition的值會(huì)+1,指向下一個(gè)可以放入的位置。capacity = limit ,為緩沖區(qū)容量的值。

flip()方法

  • flip()方法會(huì)切換對(duì)緩沖區(qū)的操作模式,由寫->讀 / 讀->寫
  • 進(jìn)行該操作后
    • 如果是寫模式->讀模式,position = 0 , limit 指向最后一個(gè)元素的下一個(gè)位置,capacity不變
    • 如果是讀->寫,則恢復(fù)為put()方法中的值

get()方法

  • get()方法會(huì)讀取緩沖區(qū)中的一個(gè)值
  • 進(jìn)行該操作后,position會(huì)+1,如果超過了limit則會(huì)拋出異常
  • 注意:get(i)方法不會(huì)改變position的值

rewind()方法

  • 該方法只能在讀模式下使用
  • rewind()方法后,會(huì)恢復(fù)position、limit和capacity的值,變?yōu)檫M(jìn)行g(shù)et()前的值

clean()方法

  • clean()方法會(huì)將緩沖區(qū)中的各個(gè)屬性恢復(fù)為最初的狀態(tài),position = 0, capacity = limit
  • 此時(shí)緩沖區(qū)的數(shù)據(jù)依然存在,處于“被遺忘”狀態(tài),下次進(jìn)行寫操作時(shí)會(huì)覆蓋這些數(shù)據(jù)

mark()和reset()方法

  • mark()方法會(huì)將postion的值保存到mark屬性中
  • reset()方法會(huì)將position的值改為mark中保存的值

compact()方法

此方法為ByteBuffer的方法,而不是Buffer的方法

  • compact會(huì)把未讀完的數(shù)據(jù)向前壓縮,然后切換到寫模式
  • 數(shù)據(jù)前移后,原位置的值并未清零,寫時(shí)會(huì)覆蓋之前的值

clear() VS compact()

clear只是對(duì)position、limit、mark進(jìn)行重置,而compact在對(duì)position進(jìn)行設(shè)置,以及l(fā)imit、mark進(jìn)行重置的同時(shí),還涉及到數(shù)據(jù)在內(nèi)存中拷貝(會(huì)調(diào)用arraycopy)。所以compact比clear更耗性能。但compact能保存你未讀取的數(shù)據(jù),將新數(shù)據(jù)追加到為讀取的數(shù)據(jù)之后;而clear則不行,若你調(diào)用了clear,則未讀取的數(shù)據(jù)就無法再讀取到了

所以需要根據(jù)情況來判斷使用哪種方法進(jìn)行模式切換

方法調(diào)用及演示

ByteBuffer調(diào)試工具類

需要先導(dǎo)入netty依賴

<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.51.Final</version> </dependency> import java.nio.ByteBuffer;import io.netty.util.internal.MathUtil; import io.netty.util.internal.StringUtil; import io.netty.util.internal.MathUtil.*;/*** @author Panwen Chen* @date 2021/4/12 15:59*/ public class ByteBufferUtil {private static final char[] BYTE2CHAR = new char[256];private static final char[] HEXDUMP_TABLE = new char[256 * 4];private static final String[] HEXPADDING = new String[16];private static final String[] HEXDUMP_ROWPREFIXES = new String[65536 >>> 4];private static final String[] BYTE2HEX = new String[256];private static final String[] BYTEPADDING = new String[16];static {final char[] DIGITS = "0123456789abcdef".toCharArray();for (int i = 0; i < 256; i++) {HEXDUMP_TABLE[i << 1] = DIGITS[i >>> 4 & 0x0F];HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i & 0x0F];}int i;// Generate the lookup table for hex dump paddingsfor (i = 0; i < HEXPADDING.length; i++) {int padding = HEXPADDING.length - i;StringBuilder buf = new StringBuilder(padding * 3);for (int j = 0; j < padding; j++) {buf.append(" ");}HEXPADDING[i] = buf.toString();}// Generate the lookup table for the start-offset header in each row (up to 64KiB).for (i = 0; i < HEXDUMP_ROWPREFIXES.length; i++) {StringBuilder buf = new StringBuilder(12);buf.append(StringUtil.NEWLINE);buf.append(Long.toHexString(i << 4 & 0xFFFFFFFFL | 0x100000000L));buf.setCharAt(buf.length() - 9, '|');buf.append('|');HEXDUMP_ROWPREFIXES[i] = buf.toString();}// Generate the lookup table for byte-to-hex-dump conversionfor (i = 0; i < BYTE2HEX.length; i++) {BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i);}// Generate the lookup table for byte dump paddingsfor (i = 0; i < BYTEPADDING.length; i++) {int padding = BYTEPADDING.length - i;StringBuilder buf = new StringBuilder(padding);for (int j = 0; j < padding; j++) {buf.append(' ');}BYTEPADDING[i] = buf.toString();}// Generate the lookup table for byte-to-char conversionfor (i = 0; i < BYTE2CHAR.length; i++) {if (i <= 0x1f || i >= 0x7f) {BYTE2CHAR[i] = '.';} else {BYTE2CHAR[i] = (char) i;}}}/*** 打印所有內(nèi)容* @param buffer*/public static void debugAll(ByteBuffer buffer) {int oldlimit = buffer.limit();buffer.limit(buffer.capacity());StringBuilder origin = new StringBuilder(256);appendPrettyHexDump(origin, buffer, 0, buffer.capacity());System.out.println("+--------+-------------------- all ------------------------+----------------+");System.out.printf("position: [%d], limit: [%d]\n", buffer.position(), oldlimit);System.out.println(origin);buffer.limit(oldlimit);}/*** 打印可讀取內(nèi)容* @param buffer*/public static void debugRead(ByteBuffer buffer) {StringBuilder builder = new StringBuilder(256);appendPrettyHexDump(builder, buffer, buffer.position(), buffer.limit() - buffer.position());System.out.println("+--------+-------------------- read -----------------------+----------------+");System.out.printf("position: [%d], limit: [%d]\n", buffer.position(), buffer.limit());System.out.println(builder);}private static void appendPrettyHexDump(StringBuilder dump, ByteBuffer buf, int offset, int length) {if (MathUtil.isOutOfBounds(offset, length, buf.capacity())) {throw new IndexOutOfBoundsException("expected: " + "0 <= offset(" + offset + ") <= offset + length(" + length+ ") <= " + "buf.capacity(" + buf.capacity() + ')');}if (length == 0) {return;}dump.append(" +-------------------------------------------------+" +StringUtil.NEWLINE + " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |" +StringUtil.NEWLINE + "+--------+-------------------------------------------------+----------------+");final int startIndex = offset;final int fullRows = length >>> 4;final int remainder = length & 0xF;// Dump the rows which have 16 bytes.for (int row = 0; row < fullRows; row++) {int rowStartIndex = (row << 4) + startIndex;// Per-row prefix.appendHexDumpRowPrefix(dump, row, rowStartIndex);// Hex dumpint rowEndIndex = rowStartIndex + 16;for (int j = rowStartIndex; j < rowEndIndex; j++) {dump.append(BYTE2HEX[getUnsignedByte(buf, j)]);}dump.append(" |");// ASCII dumpfor (int j = rowStartIndex; j < rowEndIndex; j++) {dump.append(BYTE2CHAR[getUnsignedByte(buf, j)]);}dump.append('|');}// Dump the last row which has less than 16 bytes.if (remainder != 0) {int rowStartIndex = (fullRows << 4) + startIndex;appendHexDumpRowPrefix(dump, fullRows, rowStartIndex);// Hex dumpint rowEndIndex = rowStartIndex + remainder;for (int j = rowStartIndex; j < rowEndIndex; j++) {dump.append(BYTE2HEX[getUnsignedByte(buf, j)]);}dump.append(HEXPADDING[remainder]);dump.append(" |");// Ascii dumpfor (int j = rowStartIndex; j < rowEndIndex; j++) {dump.append(BYTE2CHAR[getUnsignedByte(buf, j)]);}dump.append(BYTEPADDING[remainder]);dump.append('|');}dump.append(StringUtil.NEWLINE +"+--------+-------------------------------------------------+----------------+");}private static void appendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartIndex) {if (row < HEXDUMP_ROWPREFIXES.length) {dump.append(HEXDUMP_ROWPREFIXES[row]);} else {dump.append(StringUtil.NEWLINE);dump.append(Long.toHexString(rowStartIndex & 0xFFFFFFFFL | 0x100000000L));dump.setCharAt(dump.length() - 9, '|');dump.append('|');}}public static short getUnsignedByte(ByteBuffer buffer, int index) {return (short) (buffer.get(index) & 0xFF);} } public class TestByteBuffer {public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(10);// 向buffer中寫入1個(gè)字節(jié)的數(shù)據(jù)buffer.put((byte)97);// 使用工具類,查看buffer狀態(tài)ByteBufferUtil.debugAll(buffer);// 向buffer中寫入4個(gè)字節(jié)的數(shù)據(jù)buffer.put(new byte[]{98, 99, 100, 101});ByteBufferUtil.debugAll(buffer);// 獲取數(shù)據(jù)buffer.flip();ByteBufferUtil.debugAll(buffer);System.out.println(buffer.get());System.out.println(buffer.get());ByteBufferUtil.debugAll(buffer);// 使用compact切換模式buffer.compact();ByteBufferUtil.debugAll(buffer);// 再次寫入buffer.put((byte)102);buffer.put((byte)103);ByteBufferUtil.debugAll(buffer);} }

運(yùn)行結(jié)果

// 向緩沖區(qū)寫入了一個(gè)字節(jié)的數(shù)據(jù),此時(shí)postition為1 +--------+-------------------- all ------------------------+----------------+ position: [1], limit: [10]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 61 00 00 00 00 00 00 00 00 00 |a......... | +--------+-------------------------------------------------+----------------+// 向緩沖區(qū)寫入四個(gè)字節(jié)的數(shù)據(jù),此時(shí)position為5 +--------+-------------------- all ------------------------+----------------+ position: [5], limit: [10]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 61 62 63 64 65 00 00 00 00 00 |abcde..... | +--------+-------------------------------------------------+----------------+// 調(diào)用flip切換模式,此時(shí)position為0,表示從第0個(gè)數(shù)據(jù)開始讀取 +--------+-------------------- all ------------------------+----------------+ position: [0], limit: [5]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 61 62 63 64 65 00 00 00 00 00 |abcde..... | +--------+-------------------------------------------------+----------------+ // 讀取兩個(gè)字節(jié)的數(shù)據(jù) 97 98// position變?yōu)? +--------+-------------------- all ------------------------+----------------+ position: [2], limit: [5]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 61 62 63 64 65 00 00 00 00 00 |abcde..... | +--------+-------------------------------------------------+----------------+// 調(diào)用compact切換模式,此時(shí)position及其后面的數(shù)據(jù)被壓縮到ByteBuffer前面去了 // 此時(shí)position為3,會(huì)覆蓋之前的數(shù)據(jù) +--------+-------------------- all ------------------------+----------------+ position: [3], limit: [10]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 63 64 65 64 65 00 00 00 00 00 |cdede..... | +--------+-------------------------------------------------+----------------+// 再次寫入兩個(gè)字節(jié)的數(shù)據(jù),之前的 0x64 0x65 被覆蓋 +--------+-------------------- all ------------------------+----------------+ position: [5], limit: [10]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 63 64 65 66 67 00 00 00 00 00 |cdefg..... | +--------+-------------------------------------------------+----------------+

方法二

編碼:通過StandardCharsets的encode方法獲得ByteBuffer,此時(shí)獲得的ByteBuffer為讀模式,無需通過flip切換模式

解碼:通過StandardCharsets的decoder方法解碼

public class Translate {public static void main(String[] args) {// 準(zhǔn)備兩個(gè)字符串String str1 = "hello";String str2 = "";// 通過StandardCharsets的encode方法獲得ByteBuffer// 此時(shí)獲得的ByteBuffer為讀模式,無需通過flip切換模式ByteBuffer buffer1 = StandardCharsets.UTF_8.encode(str1);ByteBufferUtil.debugAll(buffer1);// 將緩沖區(qū)中的數(shù)據(jù)轉(zhuǎn)化為字符串// 通過StandardCharsets解碼,獲得CharBuffer,再通過toString獲得字符串str2 = StandardCharsets.UTF_8.decode(buffer1).toString();System.out.println(str2);ByteBufferUtil.debugAll(buffer1);} }運(yùn)行結(jié)果 +--------+-------------------- all ------------------------+----------------+ position: [0], limit: [5]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 68 65 6c 6c 6f |hello | +--------+-------------------------------------------------+----------------+ hello +--------+-------------------- all ------------------------+----------------+ position: [5], limit: [5]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 68 65 6c 6c 6f |hello | +--------+-------------------------------------------------+----------------+方法三

編碼:字符串調(diào)用getByte()方法獲得字節(jié)數(shù)組,將字節(jié)數(shù)組傳給ByteBuffer的wrap()方法,通過該方法獲得ByteBuffer。同樣無需調(diào)用flip方法切換為讀模式

解碼:通過StandardCharsets的decoder方法解碼

public class Translate {public static void main(String[] args) {// 準(zhǔn)備兩個(gè)字符串String str1 = "hello";String str2 = "";// 通過StandardCharsets的encode方法獲得ByteBuffer// 此時(shí)獲得的ByteBuffer為讀模式,無需通過flip切換模式ByteBuffer buffer1 = ByteBuffer.wrap(str1.getBytes());ByteBufferUtil.debugAll(buffer1);// 將緩沖區(qū)中的數(shù)據(jù)轉(zhuǎn)化為字符串// 通過StandardCharsets解碼,獲得CharBuffer,再通過toString獲得字符串str2 = StandardCharsets.UTF_8.decode(buffer1).toString();System.out.println(str2);ByteBufferUtil.debugAll(buffer1);} }運(yùn)行結(jié)果 +--------+-------------------- all ------------------------+----------------+ position: [0], limit: [5]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 68 65 6c 6c 6f |hello | +--------+-------------------------------------------------+----------------+ hello +--------+-------------------- all ------------------------+----------------+ position: [5], limit: [5]+-------------------------------------------------+| 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 68 65 6c 6c 6f |hello | +--------+-------------------------------------------------+----------------+


???????粘包與半包

現(xiàn)象

網(wǎng)絡(luò)上有多條數(shù)據(jù)發(fā)送給服務(wù)端,數(shù)據(jù)之間使用 \n 進(jìn)行分隔
但由于某種原因這些數(shù)據(jù)在接收時(shí),被進(jìn)行了重新組合,例如原始數(shù)據(jù)有3條為

  • Hello,world\n
  • I’m Nyima\n
  • How are you?\n

變成了下面的兩個(gè) byteBuffer (粘包,半包)

  • Hello,world\nI’m Nyima\nHo
  • w are you?\n

出現(xiàn)原因

粘包

發(fā)送方在發(fā)送數(shù)據(jù)時(shí),并不是一條一條地發(fā)送數(shù)據(jù),而是將數(shù)據(jù)整合在一起,當(dāng)數(shù)據(jù)達(dá)到一定的數(shù)量后再一起發(fā)送。這就會(huì)導(dǎo)致多條信息被放在一個(gè)緩沖區(qū)中被一起發(fā)送出去

半包

接收方的緩沖區(qū)的大小是有限的,當(dāng)接收方的緩沖區(qū)滿了以后,就需要將信息截?cái)?/strong>,等緩沖區(qū)空了以后再繼續(xù)放入數(shù)據(jù)。這就會(huì)發(fā)生一段完整的數(shù)據(jù)最后被截?cái)嗟默F(xiàn)象

解決辦法

  • 通過get(index)方法遍歷ByteBuffer,遇到分隔符時(shí)進(jìn)行處理。注意:get(index)不會(huì)改變position的值
    • 記錄該段數(shù)據(jù)長(zhǎng)度,以便于申請(qǐng)對(duì)應(yīng)大小的緩沖區(qū)
    • 將緩沖區(qū)的數(shù)據(jù)通過get()方法寫入到target中
  • 調(diào)用compact方法切換模式,因?yàn)榫彌_區(qū)中可能還有未讀的數(shù)據(jù)

二、文件編程

1、FileChannel

工作模式

FileChannel只能在阻塞模式下工作,所以無法搭配Selector

獲取

不能直接打開 FileChannel,必須通過 FileInputStream、FileOutputStream 或者 RandomAccessFile 來獲取 FileChannel,它們都有 getChannel 方法

  • 通過 FileInputStream 獲取的 channel?只能讀
  • 通過 FileOutputStream 獲取的 channel?只能寫
  • 通過 RandomAccessFile 是否能讀寫根據(jù)構(gòu)造 RandomAccessFile 時(shí)的讀寫模式?jīng)Q定

讀取

通過 FileInputStream 獲取channel,通過read方法將數(shù)據(jù)寫入到ByteBuffer中

read方法的返回值表示讀到了多少字節(jié),若讀到了文件末尾則返回-1

int readBytes = channel.read(buffer);可根據(jù)返回值判斷是否讀取完畢Copy while(channel.read(buffer) > 0) {// 進(jìn)行對(duì)應(yīng)操作... }Copy

寫入

因?yàn)閏hannel也是有大小的,所以 write 方法并不能保證一次將 buffer 中的內(nèi)容全部寫入 channel。必須需要按照以下規(guī)則進(jìn)行寫入

// 通過hasRemaining()方法查看緩沖區(qū)中是否還有數(shù)據(jù)未寫入到通道中 while(buffer.hasRemaining()) {channel.write(buffer); }Copy

關(guān)閉

通道需要close,一般情況通過try-with-resource進(jìn)行關(guān)閉,最好使用以下方法獲取strea以及channel,避免某些原因使得資源未被關(guān)閉

public class TestChannel {public static void main(String[] args) throws IOException {try (FileInputStream fis = new FileInputStream("stu.txt");FileOutputStream fos = new FileOutputStream("student.txt");FileChannel inputChannel = fis.getChannel();FileChannel outputChannel = fos.getChannel()) {// 執(zhí)行對(duì)應(yīng)操作...}} }

position

channel也擁有一個(gè)保存讀取數(shù)據(jù)位置的屬性,即position

long pos = channel.position();可以通過position(int pos)設(shè)置channel中position的值 long newPos = ...; channel.position(newPos);

設(shè)置當(dāng)前位置時(shí),如果設(shè)置為文件的末尾

  • 這時(shí)讀取會(huì)返回 -1
  • 這時(shí)寫入,會(huì)追加內(nèi)容,但要注意如果 position 超過了文件末尾,再寫入時(shí)在新內(nèi)容和原末尾之間會(huì)有空洞(00)

強(qiáng)制寫入

操作系統(tǒng)出于性能的考慮,會(huì)將數(shù)據(jù)緩存,不是立刻寫入磁盤,而是等到緩存滿了以后將所有數(shù)據(jù)一次性的寫入磁盤。可以調(diào)用?force(true)?方法將文件內(nèi)容和元數(shù)據(jù)(文件的權(quán)限等信息)立刻寫入磁盤

2、兩個(gè)Channel傳輸數(shù)據(jù)

transferTo方法

使用transferTo方法可以快速、高效地將一個(gè)channel中的數(shù)據(jù)傳輸?shù)搅硪粋€(gè)channel中,但一次只能傳輸2G的內(nèi)容

transferTo底層使用了零拷貝技術(shù)

public class TestChannel {public static void main(String[] args){try (FileInputStream fis = new FileInputStream("stu.txt");FileOutputStream fos = new FileOutputStream("student.txt");FileChannel inputChannel = fis.getChannel();FileChannel outputChannel = fos.getChannel()) {// 參數(shù):inputChannel的起始位置,傳輸數(shù)據(jù)的大小,目的channel// 返回值為傳輸?shù)臄?shù)據(jù)的字節(jié)數(shù)// transferTo一次只能傳輸2G的數(shù)據(jù)inputChannel.transferTo(0, inputChannel.size(), outputChannel);} catch (IOException e) {e.printStackTrace();}} }

當(dāng)傳輸?shù)奈募?strong>大于2G時(shí),需要使用以下方法進(jìn)行多次傳輸

public class TestChannel {public static void main(String[] args){try (FileInputStream fis = new FileInputStream("stu.txt");FileOutputStream fos = new FileOutputStream("student.txt");FileChannel inputChannel = fis.getChannel();FileChannel outputChannel = fos.getChannel()) {long size = inputChannel.size();long capacity = inputChannel.size();// 分多次傳輸while (capacity > 0) {// transferTo返回值為傳輸了的字節(jié)數(shù)capacity -= inputChannel.transferTo(size-capacity, capacity, outputChannel);}} catch (IOException e) {e.printStackTrace();}} }

3、Path與Paths

  • Path 用來表示文件路徑
  • Paths 是工具類,用來獲取 Path 實(shí)例
Path source = Paths.get("1.txt"); // 相對(duì)路徑 不帶盤符 使用 user.dir 環(huán)境變量來定位 1.txtPath source = Paths.get("d:\\1.txt"); // 絕對(duì)路徑 代表了 d:\1.txt 反斜杠需要轉(zhuǎn)義Path source = Paths.get("d:/1.txt"); // 絕對(duì)路徑 同樣代表了 d:\1.txtPath projects = Paths.get("d:\\data", "projects"); // 代表了 d:\data\projectsCopy
  • .?代表了當(dāng)前路徑
  • ..?代表了上一級(jí)路徑

例如目錄結(jié)構(gòu)如下

d:|- data|- projects|- a|- b

代碼

Path path = Paths.get("d:\\data\\projects\\a\\..\\b"); System.out.println(path); System.out.println(path.normalize()); // 正常化路徑 會(huì)去除 . 以及 ..

輸出結(jié)果為

d:\data\projects\a\..\b d:\data\projects\b

4、Files

查找

檢查文件是否存在

Path path = Paths.get("helloword/data.txt"); System.out.println(Files.exists(path));

創(chuàng)建

創(chuàng)建一級(jí)目錄

Path path = Paths.get("helloword/d1"); Files.createDirectory(path);
  • 如果目錄已存在,會(huì)拋異常 FileAlreadyExistsException
  • 不能一次創(chuàng)建多級(jí)目錄,否則會(huì)拋異常 NoSuchFileException

創(chuàng)建多級(jí)目錄用

Path path = Paths.get("helloword/d1/d2"); Files.createDirectories(path);Copy拷貝及移動(dòng)

拷貝文件

Path source = Paths.get("helloword/data.txt"); Path target = Paths.get("helloword/target.txt");Files.copy(source, target);Copy
  • 如果文件已存在,會(huì)拋異常 FileAlreadyExistsException

如果希望用 source?覆蓋掉 target,需要用 StandardCopyOption 來控制

Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);Copy

移動(dòng)文件

Path source = Paths.get("helloword/data.txt"); Path target = Paths.get("helloword/data.txt");Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);StandardCopyOption.ATOMIC_MOVE 保證文件移動(dòng)的原子性

刪除

刪除文件

Path target = Paths.get("helloword/target.txt");

三、網(wǎng)絡(luò)編程

1、阻塞

  • 阻塞模式下,相關(guān)方法都會(huì)導(dǎo)致線程暫停
    • ServerSocketChannel.accept 會(huì)在沒有連接建立時(shí)讓線程暫停
    • SocketChannel.read 會(huì)在通道中沒有數(shù)據(jù)可讀時(shí)讓線程暫停
    • 阻塞的表現(xiàn)其實(shí)就是線程暫停了,暫停期間不會(huì)占用 cpu,但線程相當(dāng)于閑置
  • 單線程下,阻塞方法之間相互影響,幾乎不能正常工作,需要多線程支持
  • 但多線程下,有新的問題,體現(xiàn)在以下方面
    • 32 位 jvm 一個(gè)線程 320k,64 位 jvm 一個(gè)線程 1024k,如果連接數(shù)過多,必然導(dǎo)致 OOM,并且線程太多,反而會(huì)因?yàn)轭l繁上下文切換導(dǎo)致性能降低
    • 可以采用線程池技術(shù)來減少線程數(shù)和線程上下文切換,但治標(biāo)不治本,如果有很多連接建立,但長(zhǎng)時(shí)間 inactive,會(huì)阻塞線程池中所有線程,因此不適合長(zhǎng)連接,只適合短連接

服務(wù)端代碼

public class Server {public static void main(String[] args) {// 創(chuàng)建緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(16);// 獲得服務(wù)器通道try(ServerSocketChannel server = ServerSocketChannel.open()) {// 為服務(wù)器通道綁定端口server.bind(new InetSocketAddress(8080));// 用戶存放連接的集合ArrayList<SocketChannel> channels = new ArrayList<>();// 循環(huán)接收連接while (true) {System.out.println("before connecting...");// 沒有連接時(shí),會(huì)阻塞線程SocketChannel socketChannel = server.accept();System.out.println("after connecting...");channels.add(socketChannel);// 循環(huán)遍歷集合中的連接for(SocketChannel channel : channels) {System.out.println("before reading");// 處理通道中的數(shù)據(jù)// 當(dāng)通道中沒有數(shù)據(jù)可讀時(shí),會(huì)阻塞線程channel.read(buffer);buffer.flip();ByteBufferUtil.debugRead(buffer);buffer.clear();System.out.println("after reading");}}} catch (IOException e) {e.printStackTrace();}} }

?客戶端代碼

public class Client {public static void main(String[] args) {try (SocketChannel socketChannel = SocketChannel.open()) {// 建立連接socketChannel.connect(new InetSocketAddress("localhost", 8080));System.out.println("waiting...");} catch (IOException e) {e.printStackTrace();}} }

運(yùn)行結(jié)果

  • 客戶端-服務(wù)器建立連接前:服務(wù)器端因accept阻塞

  • 客戶端-服務(wù)器建立連接后,客戶端發(fā)送消息前:服務(wù)器端因通道為空被阻塞

  • 客戶端發(fā)送數(shù)據(jù)后,服務(wù)器處理通道中的數(shù)據(jù)。再次進(jìn)入循環(huán)時(shí),再次被accept阻塞

  • 之前的客戶端再次發(fā)送消息,服務(wù)器端因?yàn)楸籥ccept阻塞,無法處理之前客戶端發(fā)送到通道中的信息

2、非阻塞

  • 可以通過ServerSocketChannel的configureBlocking(false)方法將獲得連接設(shè)置為非阻塞的。此時(shí)若沒有連接,accept會(huì)返回null

  • 可以通過SocketChannel的configureBlocking(false)方法將從通道中讀取數(shù)據(jù)設(shè)置為非阻塞的。若此時(shí)通道中沒有數(shù)據(jù)可讀,read會(huì)返回-1

服務(wù)器代碼如下

public class Server {public static void main(String[] args) {// 創(chuàng)建緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(16);// 獲得服務(wù)器通道try(ServerSocketChannel server = ServerSocketChannel.open()) {// 為服務(wù)器通道綁定端口server.bind(new InetSocketAddress(8080));// 用戶存放連接的集合ArrayList<SocketChannel> channels = new ArrayList<>();// 循環(huán)接收連接while (true) {// 設(shè)置為非阻塞模式,沒有連接時(shí)返回null,不會(huì)阻塞線程server.configureBlocking(false);SocketChannel socketChannel = server.accept();// 通道不為空時(shí)才將連接放入到集合中if (socketChannel != null) {System.out.println("after connecting...");channels.add(socketChannel);}// 循環(huán)遍歷集合中的連接for(SocketChannel channel : channels) {// 處理通道中的數(shù)據(jù)// 設(shè)置為非阻塞模式,若通道中沒有數(shù)據(jù),會(huì)返回0,不會(huì)阻塞線程channel.configureBlocking(false);int read = channel.read(buffer);if(read > 0) {buffer.flip();ByteBufferUtil.debugRead(buffer);buffer.clear();System.out.println("after reading");}}}} catch (IOException e) {e.printStackTrace();}} }

這樣寫存在一個(gè)問題,因?yàn)樵O(shè)置為了非阻塞,會(huì)一直執(zhí)行while(true)中的代碼,CPU一直處于忙碌狀態(tài),會(huì)使得性能變低,所以實(shí)際情況中不使用這種方法處理請(qǐng)求

3、Selector

多路復(fù)用

單線程可以配合 Selector 完成對(duì)多個(gè) Channel 可讀寫事件的監(jiān)控,這稱之為多路復(fù)用

  • 多路復(fù)用僅針對(duì)網(wǎng)絡(luò) IO,普通文件 IO?無法利用多路復(fù)用
  • 如果不用 Selector 的非阻塞模式,線程大部分時(shí)間都在做無用功,而 Selector 能夠保證
    • 有可連接事件時(shí)才去連接
    • 有可讀事件才去讀取
    • 有可寫事件才去寫入
      • 限于網(wǎng)絡(luò)傳輸能力,Channel 未必時(shí)時(shí)可寫,一旦 Channel 可寫,會(huì)觸發(fā) Selector 的可寫事件

4、使用及Accpet事件

要使用Selector實(shí)現(xiàn)多路復(fù)用,服務(wù)端代碼如下改進(jìn)

public class SelectServer {public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(16);// 獲得服務(wù)器通道try(ServerSocketChannel server = ServerSocketChannel.open()) {server.bind(new InetSocketAddress(8080));// 創(chuàng)建選擇器Selector selector = Selector.open();// 通道必須設(shè)置為非阻塞模式server.configureBlocking(false);// 將通道注冊(cè)到選擇器中,并設(shè)置感興趣的事件server.register(selector, SelectionKey.OP_ACCEPT);while (true) {// 若沒有事件就緒,線程會(huì)被阻塞,反之不會(huì)被阻塞。從而避免了CPU空轉(zhuǎn)// 返回值為就緒的事件個(gè)數(shù)int ready = selector.select();System.out.println("selector ready counts : " + ready);// 獲取所有事件Set<SelectionKey> selectionKeys = selector.selectedKeys();// 使用迭代器遍歷事件Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();// 判斷key的類型if(key.isAcceptable()) {// 獲得key對(duì)應(yīng)的channelServerSocketChannel channel = (ServerSocketChannel) key.channel();System.out.println("before accepting...");// 獲取連接并處理,而且是必須處理,否則需要取消SocketChannel socketChannel = channel.accept();System.out.println("after accepting...");// 處理完畢后移除iterator.remove();}}}} catch (IOException e) {e.printStackTrace();}} }

步驟解析

  • 獲得選擇器Selector
Selector selector = Selector.open();Copy
  • 通道設(shè)置為非阻塞模式,并注冊(cè)到選擇器中,并設(shè)置感興趣的事件
    • channel 必須工作在非阻塞模式
    • FileChannel 沒有非阻塞模式,因此不能配合 selector 一起使用
    • 綁定的事件類型可以有
      • connect - 客戶端連接成功時(shí)觸發(fā)
      • accept - 服務(wù)器端成功接受連接時(shí)觸發(fā)
      • read - 數(shù)據(jù)可讀入時(shí)觸發(fā),有因?yàn)榻邮漳芰θ?#xff0c;數(shù)據(jù)暫不能讀入的情況
      • write - 數(shù)據(jù)可寫出時(shí)觸發(fā),有因?yàn)榘l(fā)送能力弱,數(shù)據(jù)暫不能寫出的情況
// 通道必須設(shè)置為非阻塞模式 server.configureBlocking(false); // 將通道注冊(cè)到選擇器中,并設(shè)置感興趣的實(shí)踐 server.register(selector, SelectionKey.OP_ACCEPT);
  • 通過Selector監(jiān)聽事件,并獲得就緒的通道個(gè)數(shù),若沒有通道就緒,線程會(huì)被阻塞

    • 阻塞直到綁定事件發(fā)生

      int count = selector.select();阻塞直到綁定事件發(fā)生,或是超時(shí)(時(shí)間單位為 ms)???????
  • int count = selector.select(long timeout);
  • 不會(huì)阻塞,也就是不管有沒有事件,立刻返回,自己根據(jù)返回值檢查是否有事件

    int count = selector.selectNow();
  • 獲取就緒事件并得到對(duì)應(yīng)的通道,然后進(jìn)行處理

// 獲取所有事件 Set<SelectionKey> selectionKeys = selector.selectedKeys();// 使用迭代器遍歷事件 Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();// 判斷key的類型,此處為Accept類型if(key.isAcceptable()) {// 獲得key對(duì)應(yīng)的channelServerSocketChannel channel = (ServerSocketChannel) key.channel();// 獲取連接并處理,而且是必須處理,否則需要取消SocketChannel socketChannel = channel.accept();// 處理完畢后移除iterator.remove();} }事件發(fā)生后能否不處理

事件發(fā)生后,要么處理,要么取消(cancel),不能什么都不做,否則下次該事件仍會(huì)觸發(fā),這是因?yàn)?nio 底層使用的是水平觸發(fā)

Level_triggered(水平觸發(fā)):當(dāng)被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時(shí),epoll_wait()會(huì)通知處理程序去讀寫。如果這次沒有把數(shù)據(jù)一次性全部讀寫完(如讀寫緩沖區(qū)太小),那么下次調(diào)用 epoll_wait()時(shí),它還會(huì)通知你在上沒讀寫完的文件描述符上繼續(xù)讀寫,當(dāng)然如果你一直不去讀寫,它會(huì)一直通知你!!!如果系統(tǒng)中有大量你不需要讀寫的就緒文件描述符,而它們每次都會(huì)返回,這樣會(huì)大大降低處理程序檢索自己關(guān)心的就緒文件描述符的效率!!!

Edge_triggered(邊緣觸發(fā)):當(dāng)被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時(shí),epoll_wait()會(huì)通知處理程序去讀寫。如果這次沒有把數(shù)據(jù)全部讀寫完(如讀寫緩沖區(qū)太小),那么下次調(diào)用epoll_wait()時(shí),它不會(huì)通知你,也就是它只會(huì)通知你一次,直到該文件描述符上出現(xiàn)第二次可讀寫事件才會(huì)通知你!!!這種模式比水平觸發(fā)效率高,系統(tǒng)不會(huì)充斥大量你不關(guān)心的就緒文件描述符!!!

5、Read事件

  • 在Accept事件中,若有客戶端與服務(wù)器端建立了連接,需要將其對(duì)應(yīng)的SocketChannel設(shè)置為非阻塞,并注冊(cè)到選擇其中
  • 添加Read事件,觸發(fā)后進(jìn)行讀取操作
public class SelectServer {public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(16);// 獲得服務(wù)器通道try(ServerSocketChannel server = ServerSocketChannel.open()) {server.bind(new InetSocketAddress(8080));// 創(chuàng)建選擇器Selector selector = Selector.open();// 通道必須設(shè)置為非阻塞模式server.configureBlocking(false);// 將通道注冊(cè)到選擇器中,并設(shè)置感興趣的實(shí)踐server.register(selector, SelectionKey.OP_ACCEPT);// 為serverKey設(shè)置感興趣的事件while (true) {// 若沒有事件就緒,線程會(huì)被阻塞,反之不會(huì)被阻塞。從而避免了CPU空轉(zhuǎn)// 返回值為就緒的事件個(gè)數(shù)int ready = selector.select();System.out.println("selector ready counts : " + ready);// 獲取所有事件Set<SelectionKey> selectionKeys = selector.selectedKeys();// 使用迭代器遍歷事件Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();// 判斷key的類型if(key.isAcceptable()) {// 獲得key對(duì)應(yīng)的channelServerSocketChannel channel = (ServerSocketChannel) key.channel();System.out.println("before accepting...");// 獲取連接SocketChannel socketChannel = channel.accept();System.out.println("after accepting...");// 設(shè)置為非阻塞模式,同時(shí)將連接的通道也注冊(cè)到選擇其中socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);// 處理完畢后移除iterator.remove();} else if (key.isReadable()) {SocketChannel channel = (SocketChannel) key.channel();System.out.println("before reading...");channel.read(buffer);System.out.println("after reading...");buffer.flip();ByteBufferUtil.debugRead(buffer);buffer.clear();// 處理完畢后移除iterator.remove();}}}} catch (IOException e) {e.printStackTrace();}} }


???????刪除事件

當(dāng)處理完一個(gè)事件后,一定要調(diào)用迭代器的remove方法移除對(duì)應(yīng)事件,否則會(huì)出現(xiàn)錯(cuò)誤。原因如下

以我們上面的?Read事件?的代碼為例

  • 當(dāng)調(diào)用了 server.register(selector, SelectionKey.OP_ACCEPT)后,Selector中維護(hù)了一個(gè)集合,用于存放SelectionKey以及其對(duì)應(yīng)的通道

    // WindowsSelectorImpl 中的 SelectionKeyImpl數(shù)組 private SelectionKeyImpl[] channelArray = new SelectionKeyImpl[8]; public class SelectionKeyImpl extends AbstractSelectionKey {// Key對(duì)應(yīng)的通道final SelChImpl channel;... }

  • 當(dāng)選擇器中的通道對(duì)應(yīng)的事件發(fā)生后,selecionKey會(huì)被放到另一個(gè)集合中,但是selecionKey不會(huì)自動(dòng)移除,所以需要我們?cè)谔幚硗暌粋€(gè)事件后,通過迭代器手動(dòng)移除其中的selecionKey。否則會(huì)導(dǎo)致已被處理過的事件再次被處理,就會(huì)引發(fā)錯(cuò)誤

  • 斷開處理

當(dāng)客戶端與服務(wù)器之間的連接斷開時(shí),會(huì)給服務(wù)器端發(fā)送一個(gè)讀事件,對(duì)異常斷開和正常斷開需要加以不同的方式進(jìn)行處理

  • 正常斷開

    • 正常斷開時(shí),服務(wù)器端的channel.read(buffer)方法的返回值為-1,所以當(dāng)結(jié)束到返回值為-1時(shí),需要調(diào)用key的cancel方法取消此事件,并在取消后移除該事件

      int read = channel.read(buffer); // 斷開連接時(shí),客戶端會(huì)向服務(wù)器發(fā)送一個(gè)寫事件,此時(shí)read的返回值為-1 if(read == -1) {// 取消該事件的處理key.cancel();channel.close(); } else {... } // 取消或者處理,都需要移除key iterator.remove();

      異常斷開

    • 異常斷開時(shí),會(huì)拋出IOException異常, 在try-catch的catch塊中捕獲異常并調(diào)用key的cancel方法即可

消息邊界

不處理消息邊界存在的問題

將緩沖區(qū)的大小設(shè)置為4個(gè)字節(jié),發(fā)送2個(gè)漢字(你好),通過decode解碼并打印時(shí),會(huì)出現(xiàn)亂碼

ByteBuffer buffer = ByteBuffer.allocate(4); // 解碼并打印 System.out.println(StandardCharsets.UTF_8.decode(buffer)); 你� ��

這是因?yàn)閁TF-8字符集下,1個(gè)漢字占用3個(gè)字節(jié),此時(shí)緩沖區(qū)大小為4個(gè)字節(jié),一次讀時(shí)間無法處理完通道中的所有數(shù)據(jù),所以一共會(huì)觸發(fā)兩次讀事件。這就導(dǎo)致?你好?的?好?字被拆分為了前半部分和后半部分發(fā)送,解碼時(shí)就會(huì)出現(xiàn)問題

處理消息邊界

傳輸?shù)奈谋究赡苡幸韵氯N情況

  • 文本大于緩沖區(qū)大小
    • 此時(shí)需要將緩沖區(qū)進(jìn)行擴(kuò)容
  • 發(fā)生半包現(xiàn)象
  • 發(fā)生粘包現(xiàn)象

解決思路大致有以下三種

  • 固定消息長(zhǎng)度,數(shù)據(jù)包大小一樣,服務(wù)器按預(yù)定長(zhǎng)度讀取,當(dāng)發(fā)送的數(shù)據(jù)較少時(shí),需要將數(shù)據(jù)進(jìn)行填充,直到長(zhǎng)度與消息規(guī)定長(zhǎng)度一致。缺點(diǎn)是浪費(fèi)帶寬
  • 另一種思路是按分隔符拆分,缺點(diǎn)是效率低,需要一個(gè)一個(gè)字符地去匹配分隔符
  • TLV 格式,即 Type 類型、Length 長(zhǎng)度、Value 數(shù)據(jù)(也就是在消息開頭用一些空間存放后面數(shù)據(jù)的長(zhǎng)度),如HTTP請(qǐng)求頭中的Content-Type與Content-Length。類型和長(zhǎng)度已知的情況下,就可以方便獲取消息大小,分配合適的 buffer,缺點(diǎn)是 buffer 需要提前分配,如果內(nèi)容過大,則影響 server 吞吐量
    • Http 1.1 是 TLV 格式
    • Http 2.0 是 LTV 格式

下文的消息邊界處理方式為第二種:按分隔符拆分

附件與擴(kuò)容

Channel的register方法還有第三個(gè)參數(shù):附件,可以向其中放入一個(gè)Object類型的對(duì)象,該對(duì)象會(huì)與登記的Channel以及其對(duì)應(yīng)的SelectionKey綁定,可以從SelectionKey獲取到對(duì)應(yīng)通道的附件

public final SelectionKey register(Selector sel, int ops, Object att)可通過SelectionKey的attachment()方法獲得附件 ByteBuffer buffer = (ByteBuffer) key.attachment();

我們需要在Accept事件發(fā)生后,將通道注冊(cè)到Selector中時(shí),對(duì)每個(gè)通道添加一個(gè)ByteBuffer附件,讓每個(gè)通道發(fā)生讀事件時(shí)都使用自己的通道,避免與其他通道發(fā)生沖突而導(dǎo)致問題

// 設(shè)置為非阻塞模式,同時(shí)將連接的通道也注冊(cè)到選擇其中,同時(shí)設(shè)置附件 socketChannel.configureBlocking(false); ByteBuffer buffer = ByteBuffer.allocate(16); // 添加通道對(duì)應(yīng)的Buffer附件 socketChannel.register(selector, SelectionKey.OP_READ, buffer);

當(dāng)Channel中的數(shù)據(jù)大于緩沖區(qū)時(shí),需要對(duì)緩沖區(qū)進(jìn)行擴(kuò)容操作。此代碼中的擴(kuò)容的判定方法:Channel調(diào)用compact方法后,的position與limit相等,說明緩沖區(qū)中的數(shù)據(jù)并未被讀取(容量太小),此時(shí)創(chuàng)建新的緩沖區(qū),其大小擴(kuò)大為兩倍。同時(shí)還要將舊緩沖區(qū)中的數(shù)據(jù)拷貝到新的緩沖區(qū)中,同時(shí)調(diào)用SelectionKey的attach方法將新的緩沖區(qū)作為新的附件放入SelectionKey中

// 如果緩沖區(qū)太小,就進(jìn)行擴(kuò)容 if (buffer.position() == buffer.limit()) {ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity()*2);// 將舊buffer中的內(nèi)容放入新的buffer中ewBuffer.put(buffer);// 將新buffer作為附件放到key中key.attach(newBuffer); }改造后的服務(wù)器代碼如下 public class SelectServer {public static void main(String[] args) {// 獲得服務(wù)器通道try(ServerSocketChannel server = ServerSocketChannel.open()) {server.bind(new InetSocketAddress(8080));// 創(chuàng)建選擇器Selector selector = Selector.open();// 通道必須設(shè)置為非阻塞模式server.configureBlocking(false);// 將通道注冊(cè)到選擇器中,并設(shè)置感興趣的事件server.register(selector, SelectionKey.OP_ACCEPT);// 為serverKey設(shè)置感興趣的事件while (true) {// 若沒有事件就緒,線程會(huì)被阻塞,反之不會(huì)被阻塞。從而避免了CPU空轉(zhuǎn)// 返回值為就緒的事件個(gè)數(shù)int ready = selector.select();System.out.println("selector ready counts : " + ready);// 獲取所有事件Set<SelectionKey> selectionKeys = selector.selectedKeys();// 使用迭代器遍歷事件Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();// 判斷key的類型if(key.isAcceptable()) {// 獲得key對(duì)應(yīng)的channelServerSocketChannel channel = (ServerSocketChannel) key.channel();System.out.println("before accepting...");// 獲取連接SocketChannel socketChannel = channel.accept();System.out.println("after accepting...");// 設(shè)置為非阻塞模式,同時(shí)將連接的通道也注冊(cè)到選擇其中,同時(shí)設(shè)置附件socketChannel.configureBlocking(false);ByteBuffer buffer = ByteBuffer.allocate(16);socketChannel.register(selector, SelectionKey.OP_READ, buffer);// 處理完畢后移除iterator.remove();} else if (key.isReadable()) {SocketChannel channel = (SocketChannel) key.channel();System.out.println("before reading...");// 通過key獲得附件(buffer)ByteBuffer buffer = (ByteBuffer) key.attachment();int read = channel.read(buffer);if(read == -1) {key.cancel();channel.close();} else {// 通過分隔符來分隔buffer中的數(shù)據(jù)split(buffer);// 如果緩沖區(qū)太小,就進(jìn)行擴(kuò)容if (buffer.position() == buffer.limit()) {ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity()*2);// 將舊buffer中的內(nèi)容放入新的buffer中buffer.flip();newBuffer.put(buffer);// 將新buffer放到key中作為附件key.attach(newBuffer);}}System.out.println("after reading...");// 處理完畢后移除iterator.remove();}}}} catch (IOException e) {e.printStackTrace();}}private static void split(ByteBuffer buffer) {buffer.flip();for(int i = 0; i < buffer.limit(); i++) {// 遍歷尋找分隔符// get(i)不會(huì)移動(dòng)positionif (buffer.get(i) == '\n') {// 緩沖區(qū)長(zhǎng)度int length = i+1-buffer.position();ByteBuffer target = ByteBuffer.allocate(length);// 將前面的內(nèi)容寫入target緩沖區(qū)for(int j = 0; j < length; j++) {// 將buffer中的數(shù)據(jù)寫入target中target.put(buffer.get());}// 打印結(jié)果ByteBufferUtil.debugAll(target);}}// 切換為寫模式,但是緩沖區(qū)可能未讀完,這里需要使用compactbuffer.compact();} }Copy

ByteBuffer的大小分配

  • 每個(gè) channel 都需要記錄可能被切分的消息,因?yàn)?ByteBuffer 不能被多個(gè) channel 共同使用,因此需要為每個(gè) channel 維護(hù)一個(gè)獨(dú)立的 ByteBuffer
  • ByteBuffer 不能太大,比如一個(gè) ByteBuffer 1Mb 的話,要支持百萬連接就要 1Tb 內(nèi)存,因此需要設(shè)計(jì)大小可變的 ByteBuffer
  • 分配思路可以參考
    • 一種思路是首先分配一個(gè)較小的 buffer,例如 4k,如果發(fā)現(xiàn)數(shù)據(jù)不夠,再分配 8k 的 buffer,將 4k buffer 內(nèi)容拷貝至 8k buffer,優(yōu)點(diǎn)是消息連續(xù)容易處理,缺點(diǎn)是數(shù)據(jù)拷貝耗費(fèi)性能
      • 參考實(shí)現(xiàn)?Java Resizable Array
    • 另一種思路是用多個(gè)數(shù)組組成 buffer,一個(gè)數(shù)組不夠,把多出來的內(nèi)容寫入新的數(shù)組,與前面的區(qū)別是消息存儲(chǔ)不連續(xù)解析復(fù)雜,優(yōu)點(diǎn)是避免了拷貝引起的性能損耗

6、Write事件

服務(wù)器通過Buffer向通道中寫入數(shù)據(jù)時(shí),可能因?yàn)橥ǖ廊萘啃∮贐uffer中的數(shù)據(jù)大小,導(dǎo)致無法一次性將Buffer中的數(shù)據(jù)全部寫入到Channel中,這時(shí)便需要分多次寫入,具體步驟如下

  • 執(zhí)行一次寫操作,向?qū)uffer中的內(nèi)容寫入到SocketChannel中,然后判斷Buffer中是否還有數(shù)據(jù)

  • 若Buffer中還有數(shù)據(jù),則需要將SockerChannel注冊(cè)到Seletor中,并關(guān)注寫事件,同時(shí)將未寫完的Buffer作為附件一起放入到SelectionKey中

    int write = socket.write(buffer); // 通道中可能無法放入緩沖區(qū)中的所有數(shù)據(jù) if (buffer.hasRemaining()) {// 注冊(cè)到Selector中,關(guān)注可寫事件,并將buffer添加到key的附件中socket.configureBlocking(false);socket.register(selector, SelectionKey.OP_WRITE, buffer); }
  • 添加寫事件的相關(guān)操作key.isWritable(),對(duì)Buffer再次進(jìn)行寫操作

    • 每次寫后需要判斷Buffer中是否還有數(shù)據(jù)(是否寫完)。若寫完,需要移除SelecionKey中的Buffer附件,避免其占用過多內(nèi)存,同時(shí)還需移除對(duì)寫事件的關(guān)注
    SocketChannel socket = (SocketChannel) key.channel(); // 獲得buffer ByteBuffer buffer = (ByteBuffer) key.attachment(); // 執(zhí)行寫操作 int write = socket.write(buffer); System.out.println(write); // 如果已經(jīng)完成了寫操作,需要移除key中的附件,同時(shí)不再對(duì)寫事件感興趣 if (!buffer.hasRemaining()) {key.attach(null);key.interestOps(0);

整體代碼如下

public class WriteServer {public static void main(String[] args) {try(ServerSocketChannel server = ServerSocketChannel.open()) {server.bind(new InetSocketAddress(8080));server.configureBlocking(false);Selector selector = Selector.open();server.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();// 處理后就移除事件iterator.remove();if (key.isAcceptable()) {// 獲得客戶端的通道SocketChannel socket = server.accept();// 寫入數(shù)據(jù)StringBuilder builder = new StringBuilder();for(int i = 0; i < 500000000; i++) {builder.append("a");}ByteBuffer buffer = StandardCharsets.UTF_8.encode(builder.toString());// 先執(zhí)行一次Buffer->Channel的寫入,如果未寫完,就添加一個(gè)可寫事件int write = socket.write(buffer);System.out.println(write);// 通道中可能無法放入緩沖區(qū)中的所有數(shù)據(jù)if (buffer.hasRemaining()) {// 注冊(cè)到Selector中,關(guān)注可寫事件,并將buffer添加到key的附件中socket.configureBlocking(false);socket.register(selector, SelectionKey.OP_WRITE, buffer);}} else if (key.isWritable()) {SocketChannel socket = (SocketChannel) key.channel();// 獲得bufferByteBuffer buffer = (ByteBuffer) key.attachment();// 執(zhí)行寫操作int write = socket.write(buffer);System.out.println(write);// 如果已經(jīng)完成了寫操作,需要移除key中的附件,同時(shí)不再對(duì)寫事件感興趣if (!buffer.hasRemaining()) {key.attach(null);key.interestOps(0);}}}}} catch (IOException e) {e.printStackTrace();}} }

7、優(yōu)化

多線程優(yōu)化

充分利用多核CPU,分兩組選擇器

  • 單線程配一個(gè)選擇器(Boss),專門處理 accept 事件
  • 創(chuàng)建 cpu 核心數(shù)的線程(Worker),每個(gè)線程配一個(gè)選擇器,輪流處理 read 事件

實(shí)現(xiàn)思路

  • 創(chuàng)建一個(gè)負(fù)責(zé)處理Accept事件的Boss線程,與多個(gè)負(fù)責(zé)處理Read事件的Worker線程

  • Boss線程執(zhí)行的操作

    • 接受并處理Accepet事件,當(dāng)Accept事件發(fā)生后,調(diào)用Worker的register(SocketChannel socket)方法,讓W(xué)orker去處理Read事件,其中需要根據(jù)標(biāo)識(shí)robin去判斷將任務(wù)分配給哪個(gè)Worker

      // 創(chuàng)建固定數(shù)量的Worker Worker[] workers = new Worker[4]; // 用于負(fù)載均衡的原子整數(shù) AtomicInteger robin = new AtomicInteger(0); // 負(fù)載均衡,輪詢分配Worker workers[robin.getAndIncrement()% workers.length].register(socket);Copy
    • register(SocketChannel socket)方法會(huì)通過同步隊(duì)列完成Boss線程與Worker線程之間的通信,讓SocketChannel的注冊(cè)任務(wù)被Worker線程執(zhí)行。添加任務(wù)后需要調(diào)用selector.wakeup()來喚醒被阻塞的Selector

      public void register(final SocketChannel socket) throws IOException {// 只啟動(dòng)一次if (!started) {// 初始化操作}// 向同步隊(duì)列中添加SocketChannel的注冊(cè)事件// 在Worker線程中執(zhí)行注冊(cè)事件queue.add(new Runnable() {@Overridepublic void run() {try {socket.register(selector, SelectionKey.OP_READ);} catch (IOException e) {e.printStackTrace();}}});// 喚醒被阻塞的Selector// select類似LockSupport中的park,wakeup的原理類似LockSupport中的unparkselector.wakeup(); }Copy
  • Worker線程執(zhí)行的操作

    • 從同步隊(duì)列中獲取注冊(cè)任務(wù),并處理Read事件

實(shí)現(xiàn)代碼

public class ThreadsServer {public static void main(String[] args) {try (ServerSocketChannel server = ServerSocketChannel.open()) {// 當(dāng)前線程為Boss線程Thread.currentThread().setName("Boss");server.bind(new InetSocketAddress(8080));// 負(fù)責(zé)輪詢Accept事件的SelectorSelector boss = Selector.open();server.configureBlocking(false);server.register(boss, SelectionKey.OP_ACCEPT);// 創(chuàng)建固定數(shù)量的WorkerWorker[] workers = new Worker[4];// 用于負(fù)載均衡的原子整數(shù)AtomicInteger robin = new AtomicInteger(0);for(int i = 0; i < workers.length; i++) {workers[i] = new Worker("worker-"+i);}while (true) {boss.select();Set<SelectionKey> selectionKeys = boss.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();// BossSelector負(fù)責(zé)Accept事件if (key.isAcceptable()) {// 建立連接SocketChannel socket = server.accept();System.out.println("connected...");socket.configureBlocking(false);// socket注冊(cè)到Worker的Selector中System.out.println("before read...");// 負(fù)載均衡,輪詢分配Workerworkers[robin.getAndIncrement()% workers.length].register(socket);System.out.println("after read...");}}}} catch (IOException e) {e.printStackTrace();}}static class Worker implements Runnable {private Thread thread;private volatile Selector selector;private String name;private volatile boolean started = false;/*** 同步隊(duì)列,用于Boss線程與Worker線程之間的通信*/private ConcurrentLinkedQueue<Runnable> queue;public Worker(String name) {this.name = name;}public void register(final SocketChannel socket) throws IOException {// 只啟動(dòng)一次if (!started) {thread = new Thread(this, name);selector = Selector.open();queue = new ConcurrentLinkedQueue<>();thread.start();started = true;}// 向同步隊(duì)列中添加SocketChannel的注冊(cè)事件// 在Worker線程中執(zhí)行注冊(cè)事件queue.add(new Runnable() {@Overridepublic void run() {try {socket.register(selector, SelectionKey.OP_READ);} catch (IOException e) {e.printStackTrace();}}});// 喚醒被阻塞的Selector// select類似LockSupport中的park,wakeup的原理類似LockSupport中的unparkselector.wakeup();}@Overridepublic void run() {while (true) {try {selector.select();// 通過同步隊(duì)列獲得任務(wù)并運(yùn)行Runnable task = queue.poll();if (task != null) {// 獲得任務(wù),執(zhí)行注冊(cè)操作task.run();}Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while(iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();// Worker只負(fù)責(zé)Read事件if (key.isReadable()) {// 簡(jiǎn)化處理,省略細(xì)節(jié)SocketChannel socket = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(16);socket.read(buffer);buffer.flip();ByteBufferUtil.debugAll(buffer);}}} catch (IOException e) {e.printStackTrace();}}}} }

四、NIO與BIO

1、Stream與Channel

  • stream 不會(huì)自動(dòng)緩沖數(shù)據(jù),channel 會(huì)利用系統(tǒng)提供的發(fā)送緩沖區(qū)、接收緩沖區(qū)(更為底層)
  • stream 僅支持阻塞 API,channel 同時(shí)支持阻塞、非阻塞 API,網(wǎng)絡(luò) channel 可配合 selector 實(shí)現(xiàn)多路復(fù)用
  • 二者均為全雙工,即讀寫可以同時(shí)進(jìn)行
    • 雖然Stream是單向流動(dòng)的,但是它也是全雙工的

2、IO模型

  • 同步:線程自己去獲取結(jié)果(一個(gè)線程)
    • 例如:線程調(diào)用一個(gè)方法后,需要等待方法返回結(jié)果
  • 異步:線程自己不去獲取結(jié)果,而是由其它線程返回結(jié)果(至少兩個(gè)線程)
    • 例如:線程A調(diào)用一個(gè)方法后,繼續(xù)向下運(yùn)行,運(yùn)行結(jié)果由線程B返回

當(dāng)調(diào)用一次 channel.read?或 stream.read?后,會(huì)由用戶態(tài)切換至操作系統(tǒng)內(nèi)核態(tài)來完成真正數(shù)據(jù)讀取,而讀取又分為兩個(gè)階段,分別為:

  • 等待數(shù)據(jù)階段

  • 復(fù)制數(shù)據(jù)階段

根據(jù)UNIX 網(wǎng)絡(luò)編程 - 卷 I,IO模型主要有以下幾種

阻塞IO

  • 用戶線程進(jìn)行read操作時(shí),需要等待操作系統(tǒng)執(zhí)行實(shí)際的read操作,此期間用戶線程是被阻塞的,無法執(zhí)行其他操作

非阻塞IO

  • 用戶線程在一個(gè)循環(huán)中一直調(diào)用read方法,若內(nèi)核空間中還沒有數(shù)據(jù)可讀,立即返回
    • 只是在等待階段非阻塞
  • 用戶線程發(fā)現(xiàn)內(nèi)核空間中有數(shù)據(jù)后,等待內(nèi)核空間執(zhí)行復(fù)制數(shù)據(jù),待復(fù)制結(jié)束后返回結(jié)果

多路復(fù)用

Java中通過Selector實(shí)現(xiàn)多路復(fù)用

  • 當(dāng)沒有事件是,調(diào)用select方法會(huì)被阻塞住
  • 一旦有一個(gè)或多個(gè)事件發(fā)生后,就會(huì)處理對(duì)應(yīng)的事件,從而實(shí)現(xiàn)多路復(fù)用

多路復(fù)用與阻塞IO的區(qū)別

  • 阻塞IO模式下,若線程因accept事件被阻塞,發(fā)生read事件后,仍需等待accept事件執(zhí)行完成后,才能去處理read事件
  • 多路復(fù)用模式下,一個(gè)事件發(fā)生后,若另一個(gè)事件處于阻塞狀態(tài),不會(huì)影響該事件的執(zhí)行

異步IO

  • 線程1調(diào)用方法后理解返回,不會(huì)被阻塞也不需要立即獲取結(jié)果
  • 當(dāng)方法的運(yùn)行結(jié)果出來以后,由線程2將結(jié)果返回給線程1

3、零拷貝

零拷貝指的是數(shù)據(jù)無需拷貝到 JVM 內(nèi)存中,同時(shí)具有以下三個(gè)優(yōu)點(diǎn)

  • 更少的用戶態(tài)與內(nèi)核態(tài)的切換
  • 不利用 cpu 計(jì)算,減少 cpu 緩存?zhèn)喂蚕?/li>
  • 零拷貝適合小文件傳輸

傳統(tǒng) IO 問題

傳統(tǒng)的 IO 將一個(gè)文件通過 socket 寫出

File f = new File("helloword/data.txt"); RandomAccessFile file = new RandomAccessFile(file, "r");byte[] buf = new byte[(int)f.length()]; file.read(buf);Socket socket = ...; socket.getOutputStream().write(buf);Copy

內(nèi)部工作流如下

  • Java 本身并不具備 IO 讀寫能力,因此 read 方法調(diào)用后,要從 Java 程序的用戶態(tài)切換至內(nèi)核態(tài),去調(diào)用操作系統(tǒng)(Kernel)的讀能力,將數(shù)據(jù)讀入內(nèi)核緩沖區(qū)。這期間用戶線程阻塞,操作系統(tǒng)使用 DMA(Direct Memory Access)來實(shí)現(xiàn)文件讀,其間也不會(huì)使用 CPU

  • DMA 也可以理解為硬件單元,用來解放 cpu 完成文件 IO

  • 內(nèi)核態(tài)切換回用戶態(tài),將數(shù)據(jù)從內(nèi)核緩沖區(qū)讀入用戶緩沖區(qū)(即 byte[] buf),這期間?CPU 會(huì)參與拷貝,無法利用 DMA

  • 調(diào)用 write 方法,這時(shí)將數(shù)據(jù)從用戶緩沖區(qū)(byte[] buf)寫入?socket 緩沖區(qū),CPU 會(huì)參與拷貝

  • 接下來要向網(wǎng)卡寫數(shù)據(jù),這項(xiàng)能力 Java 又不具備,因此又得從用戶態(tài)切換至內(nèi)核態(tài),調(diào)用操作系統(tǒng)的寫能力,使用 DMA 將?socket 緩沖區(qū)的數(shù)據(jù)寫入網(wǎng)卡,不會(huì)使用 CPU

可以看到中間環(huán)節(jié)較多,java 的 IO 實(shí)際不是物理設(shè)備級(jí)別的讀寫,而是緩存的復(fù)制,底層的真正讀寫是操作系統(tǒng)來完成的

  • 用戶態(tài)與內(nèi)核態(tài)的切換發(fā)生了 3 次,這個(gè)操作比較重量級(jí)
  • 數(shù)據(jù)拷貝了共 4 次

NIO 優(yōu)化

通過?DirectByteBuf

  • ByteBuffer.allocate(10)
    • 底層對(duì)應(yīng) HeapByteBuffer,使用的還是 Java 內(nèi)存
  • ByteBuffer.allocateDirect(10)
    • 底層對(duì)應(yīng)DirectByteBuffer,使用的是操作系統(tǒng)內(nèi)存

大部分步驟與優(yōu)化前相同,唯有一點(diǎn):Java 可以使用 DirectByteBuffer 將堆外內(nèi)存映射到 JVM 內(nèi)存中來直接訪問使用

  • 這塊內(nèi)存不受 JVM 垃圾回收的影響,因此內(nèi)存地址固定,有助于 IO 讀寫
  • Java 中的 DirectByteBuf 對(duì)象僅維護(hù)了此內(nèi)存的虛引用,內(nèi)存回收分成兩步
    • DirectByteBuffer 對(duì)象被垃圾回收,將虛引用加入引用隊(duì)列
      • 當(dāng)引用的對(duì)象ByteBuffer被垃圾回收以后,虛引用對(duì)象Cleaner就會(huì)被放入引用隊(duì)列中,然后調(diào)用Cleaner的clean方法來釋放直接內(nèi)存
      • DirectByteBuffer 的釋放底層調(diào)用的是 Unsafe 的 freeMemory 方法
    • 通過專門線程訪問引用隊(duì)列,根據(jù)虛引用釋放堆外內(nèi)存
  • 減少了一次數(shù)據(jù)拷貝,用戶態(tài)與內(nèi)核態(tài)的切換次數(shù)沒有減少

進(jìn)一步優(yōu)化1

以下兩種方式都是零拷貝,即無需將數(shù)據(jù)拷貝到用戶緩沖區(qū)中(JVM內(nèi)存中)

底層采用了?linux 2.1?后提供的?sendFile?方法,Java 中對(duì)應(yīng)著兩個(gè) channel 調(diào)用?transferTo/transferFrom?方法拷貝數(shù)據(jù)

  • Java 調(diào)用 transferTo 方法后,要從 Java 程序的用戶態(tài)切換至內(nèi)核態(tài),使用 DMA將數(shù)據(jù)讀入內(nèi)核緩沖區(qū),不會(huì)使用 CPU

  • 數(shù)據(jù)從內(nèi)核緩沖區(qū)傳輸?shù)?socket 緩沖區(qū),CPU 會(huì)參與拷貝

  • 最后使用 DMA 將?socket 緩沖區(qū)的數(shù)據(jù)寫入網(wǎng)卡,不會(huì)使用 CPU

這種方法下

  • 只發(fā)生了1次用戶態(tài)與內(nèi)核態(tài)的切換
  • 數(shù)據(jù)拷貝了 3 次

進(jìn)一步優(yōu)化2

linux 2.4?對(duì)上述方法再次進(jìn)行了優(yōu)化

  • Java 調(diào)用 transferTo 方法后,要從 Java 程序的用戶態(tài)切換至內(nèi)核態(tài),使用 DMA將數(shù)據(jù)讀入內(nèi)核緩沖區(qū),不會(huì)使用 CPU

  • 只會(huì)將一些 offset 和 length 信息拷入?socket 緩沖區(qū),幾乎無消耗

  • 使用 DMA 將?內(nèi)核緩沖區(qū)的數(shù)據(jù)寫入網(wǎng)卡,不會(huì)使用 CPU

整個(gè)過程僅只發(fā)生了1次用戶態(tài)與內(nèi)核態(tài)的切換,數(shù)據(jù)拷貝了 2 次

4、AIO

AIO 用來解決數(shù)據(jù)復(fù)制階段的阻塞問題

  • 同步意味著,在進(jìn)行讀寫操作時(shí),線程需要等待結(jié)果,還是相當(dāng)于閑置
  • 異步意味著,在進(jìn)行讀寫操作時(shí),線程不必等待結(jié)果,而是將來由操作系統(tǒng)來通過回調(diào)方式由另外的線程來獲得結(jié)果

異步模型需要底層操作系統(tǒng)(Kernel)提供支持

  • Windows 系統(tǒng)通過 IOCP?實(shí)現(xiàn)了真正的異步 IO
  • Linux 系統(tǒng)異步 IO 在 2.6 版本引入,但其底層實(shí)現(xiàn)還是用多路復(fù)用模擬了異步 IO,性能沒有優(yōu)勢(shì)

總結(jié)

以上是生活随笔為你收集整理的中间件系列「三」netty之NIO基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

国产精品99爱免费视频 | 国产午夜手机精彩视频 | 正在播放东北夫妻内射 | 国产免费观看黄av片 | 精品成在人线av无码免费看 | 人妻少妇精品视频专区 | 亚洲日本va午夜在线电影 | 大胆欧美熟妇xx | 亚洲人成影院在线无码按摩店 | 精品国产精品久久一区免费式 | 国产真实乱对白精彩久久 | 一本色道久久综合亚洲精品不卡 | 一本久久a久久精品vr综合 | 青青久在线视频免费观看 | 窝窝午夜理论片影院 | 欧美丰满老熟妇xxxxx性 | 97夜夜澡人人爽人人喊中国片 | 啦啦啦www在线观看免费视频 | 亚洲精品美女久久久久久久 | 亚洲一区二区三区在线观看网站 | 中文精品久久久久人妻不卡 | 九九热爱视频精品 | 欧美xxxx黑人又粗又长 | 内射后入在线观看一区 | 久久精品99久久香蕉国产色戒 | 少妇被黑人到高潮喷出白浆 | 国产免费久久久久久无码 | 久久精品中文字幕一区 | 亚洲欧洲日本无在线码 | 国产精品99爱免费视频 | 对白脏话肉麻粗话av | 亚洲熟熟妇xxxx | 国产福利视频一区二区 | 久久99精品久久久久久动态图 | 免费乱码人妻系列无码专区 | 国产亚洲精品久久久ai换 | 国产精品无码永久免费888 | 成熟女人特级毛片www免费 | 日本一卡2卡3卡四卡精品网站 | 精品欧美一区二区三区久久久 | 国产精品va在线观看无码 | 成熟人妻av无码专区 | 亚洲s色大片在线观看 | 特黄特色大片免费播放器图片 | 色窝窝无码一区二区三区色欲 | 动漫av一区二区在线观看 | 欧美日韩人成综合在线播放 | 噜噜噜亚洲色成人网站 | 国内精品久久久久久中文字幕 | 亚洲一区二区三区偷拍女厕 | 蜜桃视频插满18在线观看 | 日日碰狠狠躁久久躁蜜桃 | 日韩精品a片一区二区三区妖精 | 理论片87福利理论电影 | www国产精品内射老师 | 成人欧美一区二区三区 | 永久免费观看国产裸体美女 | 在线亚洲高清揄拍自拍一品区 | 亚洲熟妇自偷自拍另类 | 亚洲国产精品成人久久蜜臀 | 国产美女精品一区二区三区 | 国产农村乱对白刺激视频 | 99精品无人区乱码1区2区3区 | 国产精品手机免费 | 亚洲精品成人av在线 | 国产精品久久久久久久9999 | 亚洲精品一区二区三区在线 | 欧美阿v高清资源不卡在线播放 | 天天躁夜夜躁狠狠是什么心态 | 国产办公室秘书无码精品99 | 亚洲一区二区三区国产精华液 | 国产美女精品一区二区三区 | 亚洲理论电影在线观看 | 香蕉久久久久久av成人 | 日韩精品无码一本二本三本色 | 亚洲精品国偷拍自产在线观看蜜桃 | 久精品国产欧美亚洲色aⅴ大片 | 国产午夜无码精品免费看 | 国产成人综合在线女婷五月99播放 | 亚洲精品一区二区三区在线 | 午夜精品一区二区三区的区别 | 领导边摸边吃奶边做爽在线观看 | 亚洲熟妇自偷自拍另类 | 精品厕所偷拍各类美女tp嘘嘘 | 成人动漫在线观看 | 亚洲中文字幕久久无码 | 色婷婷欧美在线播放内射 | 久久久久久九九精品久 | 蜜桃臀无码内射一区二区三区 | 亚洲成色www久久网站 | 色综合久久88色综合天天 | 女人高潮内射99精品 | 亚洲中文字幕无码中文字在线 | 国产精品对白交换视频 | 成在人线av无码免观看麻豆 | 男女作爱免费网站 | 一本久久a久久精品亚洲 | 丰满肥臀大屁股熟妇激情视频 | 亚洲欧洲中文日韩av乱码 | 国产精品亚洲а∨无码播放麻豆 | 亚洲精品欧美二区三区中文字幕 | 久久综合色之久久综合 | 动漫av网站免费观看 | 亚洲色成人中文字幕网站 | 久久视频在线观看精品 | 日本一区二区三区免费高清 | 欧美成人高清在线播放 | 国产明星裸体无码xxxx视频 | 久久国语露脸国产精品电影 | 丰满少妇弄高潮了www | 奇米影视7777久久精品人人爽 | 无码av中文字幕免费放 | 国产一区二区三区影院 | 亚洲中文字幕在线观看 | 欧美午夜特黄aaaaaa片 | 日日天干夜夜狠狠爱 | 久久国产精品萌白酱免费 | 成人亚洲精品久久久久软件 | 日本熟妇乱子伦xxxx | 亚洲国产精品一区二区美利坚 | 亚洲欧美国产精品专区久久 | 日韩精品无码免费一区二区三区 | 亚洲色大成网站www国产 | 又大又硬又黄的免费视频 | 国产成人无码午夜视频在线观看 | 无码一区二区三区在线观看 | 日韩人妻无码一区二区三区久久99 | 蜜桃视频韩日免费播放 | 天天做天天爱天天爽综合网 | 欧美三级不卡在线观看 | 亚洲日韩av片在线观看 | 美女极度色诱视频国产 | 色一情一乱一伦一区二区三欧美 | 偷窥村妇洗澡毛毛多 | 亚洲区欧美区综合区自拍区 | 亚洲一区二区三区在线观看网站 | 亚洲小说春色综合另类 | 激情内射日本一区二区三区 | 久久熟妇人妻午夜寂寞影院 | 亚洲日本一区二区三区在线 | 2020久久超碰国产精品最新 | 无码人妻精品一区二区三区不卡 | 国产精品成人av在线观看 | 久久aⅴ免费观看 | 日韩亚洲欧美中文高清在线 | 国产亚av手机在线观看 | 麻豆md0077饥渴少妇 | 伦伦影院午夜理论片 | 无码精品国产va在线观看dvd | 婷婷综合久久中文字幕蜜桃三电影 | 中文字幕中文有码在线 | 国产午夜无码精品免费看 | 精品无码成人片一区二区98 | 日韩精品无码一区二区中文字幕 | 麻豆人妻少妇精品无码专区 | 77777熟女视频在线观看 а天堂中文在线官网 | 99精品国产综合久久久久五月天 | 中文字幕日韩精品一区二区三区 | 亚洲の无码国产の无码影院 | 国产亚洲精品久久久久久国模美 | 亚洲精品国产精品乱码视色 | 日日摸日日碰夜夜爽av | 亚洲综合无码久久精品综合 | 国产精品无码一区二区桃花视频 | 亚洲自偷自偷在线制服 | 成人无码精品一区二区三区 | 免费看男女做好爽好硬视频 | 国产电影无码午夜在线播放 | 漂亮人妻洗澡被公强 日日躁 | 熟女俱乐部五十路六十路av | 97人妻精品一区二区三区 | 亚洲色欲色欲欲www在线 | 精品人妻人人做人人爽夜夜爽 | 色一情一乱一伦 | 亚洲精品成a人在线观看 | 亚洲gv猛男gv无码男同 | 亚洲精品国产品国语在线观看 | 亚洲欧洲日本综合aⅴ在线 | а√天堂www在线天堂小说 | 日本熟妇乱子伦xxxx | 国产内射爽爽大片视频社区在线 | 亚洲欧洲无卡二区视頻 | 黑人巨大精品欧美一区二区 | 国产sm调教视频在线观看 | 欧美熟妇另类久久久久久多毛 | 亚洲精品一区二区三区四区五区 | 亚洲一区二区观看播放 | 中文字幕无码视频专区 | 亚洲性无码av中文字幕 | 青春草在线视频免费观看 | 色综合久久久无码网中文 | 丰满少妇熟乱xxxxx视频 | 亚洲色成人中文字幕网站 | 国产真人无遮挡作爱免费视频 | 爽爽影院免费观看 | 国产精品人妻一区二区三区四 | 成人aaa片一区国产精品 | 四虎影视成人永久免费观看视频 | 夜先锋av资源网站 | 久激情内射婷内射蜜桃人妖 | 精品无码一区二区三区的天堂 | 中文字幕久久久久人妻 | 亚洲一区二区三区在线观看网站 | 中文字幕无码热在线视频 | 中文字幕av日韩精品一区二区 | 粉嫩少妇内射浓精videos | 76少妇精品导航 | 黑人粗大猛烈进出高潮视频 | 国精品人妻无码一区二区三区蜜柚 | 久久精品中文字幕大胸 | 亚洲人成网站色7799 | 日本免费一区二区三区最新 | 强奷人妻日本中文字幕 | 又粗又大又硬又长又爽 | 国产精品无码久久av | 人人爽人人澡人人人妻 | 精品国产乱码久久久久乱码 | 成人性做爰aaa片免费看不忠 | 人妻尝试又大又粗久久 | aa片在线观看视频在线播放 | 对白脏话肉麻粗话av | 蜜桃臀无码内射一区二区三区 | 中文字幕日韩精品一区二区三区 | 一区二区三区乱码在线 | 欧洲 | 免费看少妇作爱视频 | 理论片87福利理论电影 | 亚洲日韩av一区二区三区中文 | 久久久久久久人妻无码中文字幕爆 | 国产亲子乱弄免费视频 | 免费无码的av片在线观看 | 免费看男女做好爽好硬视频 | 国产欧美熟妇另类久久久 | 久久 国产 尿 小便 嘘嘘 | 小泽玛莉亚一区二区视频在线 | 国产精品99爱免费视频 | 18精品久久久无码午夜福利 | 领导边摸边吃奶边做爽在线观看 | 亚洲一区二区三区偷拍女厕 | 熟妇女人妻丰满少妇中文字幕 | 久久精品国产大片免费观看 | 一二三四在线观看免费视频 | 亚洲va欧美va天堂v国产综合 | 乱中年女人伦av三区 | 国产在线aaa片一区二区99 | 国产午夜亚洲精品不卡 | 欧美国产日韩久久mv | 中文字幕人妻无码一区二区三区 | 一个人免费观看的www视频 | 欧美兽交xxxx×视频 | 久久国产精品精品国产色婷婷 | 欧美精品一区二区精品久久 | 性做久久久久久久免费看 | 精品久久久久香蕉网 | аⅴ资源天堂资源库在线 | 亚洲中文字幕va福利 | 久久精品中文闷骚内射 | 水蜜桃av无码 | 国产精品美女久久久久av爽李琼 | 女人被男人躁得好爽免费视频 | 久久久久久久女国产乱让韩 | 免费国产黄网站在线观看 | 国产精品办公室沙发 | 国产片av国语在线观看 | 人妻尝试又大又粗久久 | 波多野结衣乳巨码无在线观看 | 国产麻豆精品一区二区三区v视界 | 国产高清av在线播放 | 国产精品成人av在线观看 | 欧美国产亚洲日韩在线二区 | 无码人妻精品一区二区三区不卡 | 久久国产精品精品国产色婷婷 | 久久国产精品萌白酱免费 | 亚洲国产欧美国产综合一区 | 亚洲欧美日韩国产精品一区二区 | 久久午夜无码鲁丝片 | 久久久精品人妻久久影视 | 在线观看国产午夜福利片 | 久久久中文久久久无码 | 人人妻在人人 | 波多野结衣一区二区三区av免费 | 伊人久久婷婷五月综合97色 | 精品水蜜桃久久久久久久 | 久久精品99久久香蕉国产色戒 | 亚洲精品中文字幕乱码 | 国产后入清纯学生妹 | 亚洲精品国产精品乱码视色 | 国产精品美女久久久久av爽李琼 | 久久亚洲精品中文字幕无男同 | 亚洲国产精品久久久天堂 | 无码中文字幕色专区 | 中文亚洲成a人片在线观看 | 狠狠色噜噜狠狠狠7777奇米 | 成人三级无码视频在线观看 | 亚洲区小说区激情区图片区 | 白嫩日本少妇做爰 | 激情内射日本一区二区三区 | 亚洲熟妇色xxxxx亚洲 | 亚洲国产欧美在线成人 | 性色欲情网站iwww九文堂 | 亚洲一区二区三区含羞草 | 少妇厨房愉情理9仑片视频 | 国产精品永久免费视频 | 娇妻被黑人粗大高潮白浆 | 欧美日韩在线亚洲综合国产人 | 漂亮人妻洗澡被公强 日日躁 | 999久久久国产精品消防器材 | 久久久久亚洲精品男人的天堂 | 亚洲精品一区二区三区大桥未久 | 一本久道高清无码视频 | 最近中文2019字幕第二页 | 天天拍夜夜添久久精品 | 国产人妻精品午夜福利免费 | 国产成人无码av一区二区 | 男人扒开女人内裤强吻桶进去 | 亚洲国产欧美国产综合一区 | 少妇高潮一区二区三区99 | 精品久久8x国产免费观看 | 亚洲成av人片在线观看无码不卡 | 中文精品无码中文字幕无码专区 | 欧美激情综合亚洲一二区 | 国产精品亚洲五月天高清 | 国产亚洲精品久久久闺蜜 | 久9re热视频这里只有精品 | 国色天香社区在线视频 | 精品成人av一区二区三区 | 久激情内射婷内射蜜桃人妖 | 在线看片无码永久免费视频 | 国内揄拍国内精品少妇国语 | 日韩av无码中文无码电影 | 国产亚洲日韩欧美另类第八页 | 综合激情五月综合激情五月激情1 | 久热国产vs视频在线观看 | 在线天堂新版最新版在线8 | 国产精品内射视频免费 | 国产精品久久久久9999小说 | 无码帝国www无码专区色综合 | 国产精品视频免费播放 | 国产乱人无码伦av在线a | 国产片av国语在线观看 | 西西人体www44rt大胆高清 | 久精品国产欧美亚洲色aⅴ大片 | 精品成人av一区二区三区 | 亚洲色欲色欲欲www在线 | 国精品人妻无码一区二区三区蜜柚 | 少妇无码吹潮 | 狂野欧美激情性xxxx | 国产猛烈高潮尖叫视频免费 | 丰满岳乱妇在线观看中字无码 | 六月丁香婷婷色狠狠久久 | 亚洲欧美精品aaaaaa片 | 又紧又大又爽精品一区二区 | 又紧又大又爽精品一区二区 | 国产乱子伦视频在线播放 | 久久无码中文字幕免费影院蜜桃 | 久久国内精品自在自线 | 国产电影无码午夜在线播放 | 色婷婷综合激情综在线播放 | 国产午夜无码视频在线观看 | 中国女人内谢69xxxx | 色一情一乱一伦一视频免费看 | 无码乱肉视频免费大全合集 | 蜜臀aⅴ国产精品久久久国产老师 | 久久久久亚洲精品中文字幕 | 亚洲 日韩 欧美 成人 在线观看 | 日本精品人妻无码77777 天堂一区人妻无码 | 无码国产色欲xxxxx视频 | 老头边吃奶边弄进去呻吟 | 玩弄少妇高潮ⅹxxxyw | 亚洲aⅴ无码成人网站国产app | 国内少妇偷人精品视频 | 夜夜躁日日躁狠狠久久av | 中文字幕无码av激情不卡 | 成人影院yy111111在线观看 | 久久午夜无码鲁丝片午夜精品 | 精品久久久中文字幕人妻 | 久久国产劲爆∧v内射 | 狠狠综合久久久久综合网 | 国产97色在线 | 免 | 国产乱人无码伦av在线a | 免费乱码人妻系列无码专区 | 中文字幕无码免费久久99 | a国产一区二区免费入口 | 中国大陆精品视频xxxx | 中文字幕乱码亚洲无线三区 | 午夜丰满少妇性开放视频 | 久久精品成人欧美大片 | 在线 国产 欧美 亚洲 天堂 | 女人被男人躁得好爽免费视频 | 日本xxxx色视频在线观看免费 | 国产真实伦对白全集 | 国产亚洲欧美日韩亚洲中文色 | 亚洲综合另类小说色区 | 亚洲精品国产精品乱码视色 | 久久综合九色综合97网 | 国产精品亚洲专区无码不卡 | 人人爽人人澡人人高潮 | 亚洲精品久久久久久久久久久 | 熟妇人妻无乱码中文字幕 | 国产无套粉嫩白浆在线 | 成人无码精品一区二区三区 | 人妻插b视频一区二区三区 | 国产精品久久久久久久9999 | 国产欧美精品一区二区三区 | 日产国产精品亚洲系列 | 性色av无码免费一区二区三区 | 精品 日韩 国产 欧美 视频 | 国产精品久久久久久无码 | 中文字幕av伊人av无码av | 亚洲一区二区三区国产精华液 | 麻豆国产人妻欲求不满谁演的 | 国产黑色丝袜在线播放 | 蜜桃av抽搐高潮一区二区 | 最新版天堂资源中文官网 | 内射爽无广熟女亚洲 | 妺妺窝人体色www在线小说 | 国产精品对白交换视频 | 中文字幕乱码中文乱码51精品 | 午夜男女很黄的视频 | 永久免费精品精品永久-夜色 | 亚洲小说春色综合另类 | 亚洲s色大片在线观看 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲成色www久久网站 | 国产人成高清在线视频99最全资源 | 成人性做爰aaa片免费看 | 免费看少妇作爱视频 | 久久精品人妻少妇一区二区三区 | 免费看男女做好爽好硬视频 | 久久这里只有精品视频9 | 亚洲日本一区二区三区在线 | 鲁大师影院在线观看 | 国产成人久久精品流白浆 | 99精品无人区乱码1区2区3区 | 亚洲精品一区二区三区四区五区 | 国产一区二区三区四区五区加勒比 | 欧美人与物videos另类 | 欧美日本免费一区二区三区 | 国产一精品一av一免费 | 精品国产一区av天美传媒 | 亚洲欧美精品aaaaaa片 | 精品亚洲韩国一区二区三区 | 人人妻人人澡人人爽欧美一区九九 | 亚洲爆乳精品无码一区二区三区 | 久久久久国色av免费观看性色 | 国产办公室秘书无码精品99 | 天天拍夜夜添久久精品 | 天堂无码人妻精品一区二区三区 | 色窝窝无码一区二区三区色欲 | 国产激情无码一区二区app | 婷婷五月综合缴情在线视频 | 国产麻豆精品精东影业av网站 | 中文字幕 亚洲精品 第1页 | 欧美亚洲国产一区二区三区 | 亚洲欧美精品aaaaaa片 | 亚洲综合久久一区二区 | 性色欲网站人妻丰满中文久久不卡 | 丰满诱人的人妻3 | 欧美亚洲国产一区二区三区 | 国产精品久久久久久亚洲毛片 | 久久无码人妻影院 | 亚洲人亚洲人成电影网站色 | 国产精品久久久久影院嫩草 | 亚洲精品一区二区三区婷婷月 | 国产精品自产拍在线观看 | 在线看片无码永久免费视频 | 亚洲欧洲中文日韩av乱码 | 亚洲成av人在线观看网址 | 99在线 | 亚洲 | 成人一在线视频日韩国产 | 最新国产乱人伦偷精品免费网站 | 日韩少妇白浆无码系列 | 97夜夜澡人人爽人人喊中国片 | 久久99精品久久久久久 | 在线a亚洲视频播放在线观看 | 无码国产乱人伦偷精品视频 | 欧美日韩在线亚洲综合国产人 | 久久婷婷五月综合色国产香蕉 | 精品无码一区二区三区爱欲 | 麻豆人妻少妇精品无码专区 | 久久精品国产亚洲精品 | 高清国产亚洲精品自在久久 | 久久精品99久久香蕉国产色戒 | 一区二区三区高清视频一 | 天天做天天爱天天爽综合网 | 一本色道久久综合亚洲精品不卡 | 成年美女黄网站色大免费全看 | 日本xxxx色视频在线观看免费 | 未满小14洗澡无码视频网站 | 麻豆成人精品国产免费 | 一本久道高清无码视频 | 国产亚洲精品久久久久久久久动漫 | 日韩少妇白浆无码系列 | 日日噜噜噜噜夜夜爽亚洲精品 | 亚洲精品国偷拍自产在线麻豆 | 欧美午夜特黄aaaaaa片 | 香港三级日本三级妇三级 | 国产乱码精品一品二品 | 国产免费观看黄av片 | 波多野结衣高清一区二区三区 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 国产精品爱久久久久久久 | 免费中文字幕日韩欧美 | 又粗又大又硬毛片免费看 | 色一情一乱一伦一区二区三欧美 | 国产午夜福利亚洲第一 | 人人妻人人澡人人爽精品欧美 | 日韩av无码一区二区三区不卡 | 国产精品视频免费播放 | 最近免费中文字幕中文高清百度 | 性生交大片免费看女人按摩摩 | 国产午夜视频在线观看 | 国产成人综合在线女婷五月99播放 | 亚洲精品久久久久avwww潮水 | av香港经典三级级 在线 | 国产精品久久久av久久久 | 久久久久人妻一区精品色欧美 | 婷婷五月综合缴情在线视频 | 亚洲精品中文字幕久久久久 | 波多野结衣av在线观看 | 亚洲天堂2017无码 | 亚洲熟妇色xxxxx欧美老妇 | 欧美日韩久久久精品a片 | 奇米影视7777久久精品人人爽 | 国产手机在线αⅴ片无码观看 | 久久久精品欧美一区二区免费 | 欧美激情综合亚洲一二区 | 精品人人妻人人澡人人爽人人 | 日韩欧美中文字幕在线三区 | 麻豆蜜桃av蜜臀av色欲av | 婷婷丁香六月激情综合啪 | 亚洲国产精华液网站w | 亚洲精品www久久久 | 国产农村妇女高潮大叫 | 日本饥渴人妻欲求不满 | 亚洲 日韩 欧美 成人 在线观看 | 久久成人a毛片免费观看网站 | 青春草在线视频免费观看 | 国产av无码专区亚洲a∨毛片 | 亚洲欧美日韩成人高清在线一区 | 久久精品人妻少妇一区二区三区 | 久久精品成人欧美大片 | 久久久久成人片免费观看蜜芽 | 成 人影片 免费观看 | 双乳奶水饱满少妇呻吟 | 日本一区二区三区免费高清 | 中文字幕+乱码+中文字幕一区 | 乱人伦人妻中文字幕无码久久网 | 亚洲中文无码av永久不收费 | 波多野结衣乳巨码无在线观看 | 亚洲精品欧美二区三区中文字幕 | 免费国产黄网站在线观看 | 成人女人看片免费视频放人 | 国产乱人伦av在线无码 | 国产精品免费大片 | 77777熟女视频在线观看 а天堂中文在线官网 | 久久久久久av无码免费看大片 | 国产综合久久久久鬼色 | 久久99精品国产.久久久久 | 76少妇精品导航 | 人妻体内射精一区二区三四 | 樱花草在线社区www | 日本丰满熟妇videos | 午夜福利一区二区三区在线观看 | 日本一卡2卡3卡四卡精品网站 | 亚洲成a人片在线观看无码3d | 内射巨臀欧美在线视频 | 亚洲中文字幕va福利 | 亚洲日韩av一区二区三区四区 | 亚洲国精产品一二二线 | 中文字幕无码视频专区 | 日本成熟视频免费视频 | 亚洲一区二区三区播放 | 日韩人妻无码一区二区三区久久99 | 伊人久久大香线蕉亚洲 | 国产乡下妇女做爰 | 东京一本一道一二三区 | 久久99精品久久久久久 | 国产人妻人伦精品1国产丝袜 | 久久久精品欧美一区二区免费 | 色狠狠av一区二区三区 | 亚洲国产精品无码久久久久高潮 | 牲交欧美兽交欧美 | 波多野结衣 黑人 | 水蜜桃色314在线观看 | 999久久久国产精品消防器材 | 狠狠噜狠狠狠狠丁香五月 | 久久精品国产99精品亚洲 | 国产一精品一av一免费 | 无码av免费一区二区三区试看 | 给我免费的视频在线观看 | 精品无人区无码乱码毛片国产 | 欧美日本免费一区二区三区 | 丰满岳乱妇在线观看中字无码 | 狂野欧美性猛交免费视频 | 久久久亚洲欧洲日产国码αv | 欧美黑人性暴力猛交喷水 | 强奷人妻日本中文字幕 | 久久久婷婷五月亚洲97号色 | 奇米影视888欧美在线观看 | 亚洲精品www久久久 | 男人扒开女人内裤强吻桶进去 | 欧美真人作爱免费视频 | 日韩av激情在线观看 | 精品人人妻人人澡人人爽人人 | 免费看少妇作爱视频 | 97资源共享在线视频 | 天天躁夜夜躁狠狠是什么心态 | 久久亚洲国产成人精品性色 | 无遮挡国产高潮视频免费观看 | 久久国产精品萌白酱免费 | 亚洲精品成人av在线 | 久久综合色之久久综合 | 久9re热视频这里只有精品 | 国产va免费精品观看 | 99riav国产精品视频 | 青草青草久热国产精品 | 国产乱人偷精品人妻a片 | 国产午夜亚洲精品不卡下载 | 欧美日韩在线亚洲综合国产人 | 蜜桃臀无码内射一区二区三区 | 中文字幕无码乱人伦 | 人人妻人人澡人人爽人人精品浪潮 | 成人欧美一区二区三区黑人免费 | 欧美黑人巨大xxxxx | 久久久中文久久久无码 | 桃花色综合影院 | 欧美 日韩 人妻 高清 中文 | 亚洲精品一区二区三区婷婷月 | 久久久成人毛片无码 | 亚洲中文字幕乱码av波多ji | 四虎永久在线精品免费网址 | 天天做天天爱天天爽综合网 | 成人欧美一区二区三区黑人免费 | 荫蒂添的好舒服视频囗交 | 国语精品一区二区三区 | 亚洲国产欧美日韩精品一区二区三区 | 人人妻人人澡人人爽欧美一区 | 免费观看黄网站 | 亚洲日韩一区二区三区 | 帮老师解开蕾丝奶罩吸乳网站 | 久久99精品久久久久婷婷 | 内射爽无广熟女亚洲 | 欧美性猛交内射兽交老熟妇 | 一区二区三区乱码在线 | 欧洲 | 国产极品视觉盛宴 | 日韩少妇白浆无码系列 | 麻豆av传媒蜜桃天美传媒 | 欧美老人巨大xxxx做受 | 亚洲午夜久久久影院 | 国产人成高清在线视频99最全资源 | 亚洲啪av永久无码精品放毛片 | 亚洲国产精品久久人人爱 | 天天摸天天碰天天添 | 亚洲精品国产第一综合99久久 | 无码精品人妻一区二区三区av | 夜先锋av资源网站 | 免费观看的无遮挡av | 成人无码视频在线观看网站 | 美女黄网站人色视频免费国产 | 精品久久久久久人妻无码中文字幕 | 国产偷国产偷精品高清尤物 | 欧美真人作爱免费视频 | 疯狂三人交性欧美 | 色诱久久久久综合网ywww | 曰本女人与公拘交酡免费视频 | 欧洲极品少妇 | 国产午夜精品一区二区三区嫩草 | 欧美怡红院免费全部视频 | 在线播放无码字幕亚洲 | 久久精品丝袜高跟鞋 | 日韩 欧美 动漫 国产 制服 | 激情综合激情五月俺也去 | 久在线观看福利视频 | 香蕉久久久久久av成人 | 国产亚洲美女精品久久久2020 | 日韩av无码一区二区三区不卡 | 国产精品18久久久久久麻辣 | 天天摸天天透天天添 | 狂野欧美性猛xxxx乱大交 | 国产成人无码区免费内射一片色欲 | 好男人社区资源 | av香港经典三级级 在线 | 欧美性生交活xxxxxdddd | 欧美兽交xxxx×视频 | 极品嫩模高潮叫床 | 永久免费精品精品永久-夜色 | 大地资源中文第3页 | 久久久久久国产精品无码下载 | 亚洲一区二区三区四区 | 国产亚洲欧美在线专区 | 久久97精品久久久久久久不卡 | 色婷婷久久一区二区三区麻豆 | 女人被男人爽到呻吟的视频 | 波多野结衣一区二区三区av免费 | 亚洲精品成人福利网站 | 国产熟妇高潮叫床视频播放 | 领导边摸边吃奶边做爽在线观看 | 日本又色又爽又黄的a片18禁 | 国产亚洲日韩欧美另类第八页 | 夜夜影院未满十八勿进 | 国内老熟妇对白xxxxhd | 无码人妻av免费一区二区三区 | 少妇人妻偷人精品无码视频 | 全黄性性激高免费视频 | 国产亚洲精品精品国产亚洲综合 | 亚洲精品久久久久avwww潮水 | 婷婷丁香五月天综合东京热 | 一二三四社区在线中文视频 | 国产一区二区三区四区五区加勒比 | 骚片av蜜桃精品一区 | 亚洲 激情 小说 另类 欧美 | 夜夜影院未满十八勿进 | 免费无码一区二区三区蜜桃大 | 亚洲天堂2017无码 | 国产精品久久久久久久影院 | 99久久精品日本一区二区免费 | 国产精品久久久久7777 | 99riav国产精品视频 | aⅴ亚洲 日韩 色 图网站 播放 | 又色又爽又黄的美女裸体网站 | 国产精品丝袜黑色高跟鞋 | 国产两女互慰高潮视频在线观看 | 性做久久久久久久久 | 亚洲一区二区三区国产精华液 | www国产精品内射老师 | 日日鲁鲁鲁夜夜爽爽狠狠 | 精品乱子伦一区二区三区 | 亚洲无人区一区二区三区 | 成在人线av无码免观看麻豆 | 在线观看免费人成视频 | 欧美老妇交乱视频在线观看 | 小鲜肉自慰网站xnxx | 午夜嘿嘿嘿影院 | 亚洲aⅴ无码成人网站国产app | 欧美人与禽zoz0性伦交 | 欧美精品在线观看 | 极品尤物被啪到呻吟喷水 | 中文精品久久久久人妻不卡 | 天天爽夜夜爽夜夜爽 | 亚洲欧洲无卡二区视頻 | 中文字幕人妻无码一夲道 | 国产成人综合色在线观看网站 | 国内丰满熟女出轨videos | 激情爆乳一区二区三区 | 国产av一区二区精品久久凹凸 | 日本精品高清一区二区 | 成 人 网 站国产免费观看 | 精品国精品国产自在久国产87 | 欧美性生交活xxxxxdddd | 欧美怡红院免费全部视频 | 青青青手机频在线观看 | 一本久久a久久精品亚洲 | 免费人成在线视频无码 | 人妻互换免费中文字幕 | 国产精品久久久久9999小说 | 亚洲 激情 小说 另类 欧美 | 欧美一区二区三区视频在线观看 | 狂野欧美性猛xxxx乱大交 | 一本色道久久综合狠狠躁 | 狠狠色噜噜狠狠狠7777奇米 | 日本熟妇人妻xxxxx人hd | 日韩少妇内射免费播放 | 亚洲乱码国产乱码精品精 | 搡女人真爽免费视频大全 | 国产电影无码午夜在线播放 | 国产午夜无码精品免费看 | 国产精品久久久av久久久 | 国产亚洲欧美在线专区 | 伊人久久婷婷五月综合97色 | 久久午夜无码鲁丝片秋霞 | 性色av无码免费一区二区三区 | 在线观看国产午夜福利片 | 国产又爽又黄又刺激的视频 | 性啪啪chinese东北女人 | 人妻少妇精品视频专区 | 国产成人综合在线女婷五月99播放 | www国产亚洲精品久久网站 | 成人亚洲精品久久久久 | 欧美人妻一区二区三区 | 男人扒开女人内裤强吻桶进去 | 欧美xxxx黑人又粗又长 | 久久精品丝袜高跟鞋 | 激情五月综合色婷婷一区二区 | 久久亚洲精品中文字幕无男同 | 色婷婷综合激情综在线播放 | 在线天堂新版最新版在线8 | 青春草在线视频免费观看 | 国内丰满熟女出轨videos | 色婷婷久久一区二区三区麻豆 | 久久精品国产99久久6动漫 | 无码av中文字幕免费放 | 国产精品国产三级国产专播 | 奇米影视888欧美在线观看 | 沈阳熟女露脸对白视频 | 亚洲精品中文字幕久久久久 | 中文字幕av伊人av无码av | 亚洲精品国偷拍自产在线麻豆 | 性啪啪chinese东北女人 | 少妇被黑人到高潮喷出白浆 | 精品少妇爆乳无码av无码专区 | 亚洲乱码中文字幕在线 | 国产黑色丝袜在线播放 | 欧美野外疯狂做受xxxx高潮 | 久久久久亚洲精品中文字幕 | 丝袜人妻一区二区三区 | 色五月丁香五月综合五月 | 桃花色综合影院 | 日本xxxx色视频在线观看免费 | 三上悠亚人妻中文字幕在线 | 97夜夜澡人人爽人人喊中国片 | 国语精品一区二区三区 | 扒开双腿吃奶呻吟做受视频 | 噜噜噜亚洲色成人网站 | 偷窥村妇洗澡毛毛多 | 亚洲啪av永久无码精品放毛片 | 激情五月综合色婷婷一区二区 | 无码国内精品人妻少妇 | 成人无码精品一区二区三区 | 日韩欧美中文字幕公布 | 国产精品久久国产三级国 | 日韩av无码一区二区三区 | 一个人看的www免费视频在线观看 | 精品成人av一区二区三区 | 亚洲日韩一区二区 | 欧美xxxxx精品 | 综合网日日天干夜夜久久 | 国产精品久久久av久久久 | 性欧美videos高清精品 | 国产香蕉尹人综合在线观看 | 国产成人无码a区在线观看视频app | 99久久精品无码一区二区毛片 | 亚洲一区二区三区偷拍女厕 | 国产精品无码久久av | 男女爱爱好爽视频免费看 | 任你躁在线精品免费 | 国产精品成人av在线观看 | 国产精品美女久久久久av爽李琼 | yw尤物av无码国产在线观看 | 久久五月精品中文字幕 | 亚洲日本va中文字幕 | 亚洲精品www久久久 | 欧美老人巨大xxxx做受 | 最近的中文字幕在线看视频 | аⅴ资源天堂资源库在线 | 午夜福利试看120秒体验区 | 国产日产欧产精品精品app | 国产农村妇女高潮大叫 | 4hu四虎永久在线观看 | 亚洲日本一区二区三区在线 | 国产亚洲精品久久久久久 | 欧洲欧美人成视频在线 | 国产成人无码区免费内射一片色欲 | 中文字幕中文有码在线 | 精品熟女少妇av免费观看 | 欧美日韩在线亚洲综合国产人 | 天干天干啦夜天干天2017 | 天堂亚洲免费视频 | 成人精品视频一区二区 | 成人影院yy111111在线观看 | 99在线 | 亚洲 | 狠狠色色综合网站 | 亚洲精品成a人在线观看 | 日韩无套无码精品 | 久久国产精品二国产精品 | 欧美老熟妇乱xxxxx | 欧美性猛交内射兽交老熟妇 | 美女张开腿让人桶 | 国产热a欧美热a在线视频 | 在线亚洲高清揄拍自拍一品区 | 全球成人中文在线 | 中文无码成人免费视频在线观看 | 人妻与老人中文字幕 | 大地资源网第二页免费观看 | 99视频精品全部免费免费观看 | 国产成人精品无码播放 | 成人女人看片免费视频放人 | 黑森林福利视频导航 | 亚洲精品国产精品乱码不卡 | 亚洲精品国产第一综合99久久 | 亲嘴扒胸摸屁股激烈网站 | 狂野欧美性猛交免费视频 | 久久久久久久女国产乱让韩 | 亚洲精品美女久久久久久久 | 久久国产精品偷任你爽任你 | 日产精品高潮呻吟av久久 | 久久zyz资源站无码中文动漫 | 性欧美熟妇videofreesex | 久久久中文久久久无码 | 性欧美大战久久久久久久 | 夜夜躁日日躁狠狠久久av | 久久午夜无码鲁丝片 | 亚洲人亚洲人成电影网站色 | 人人妻人人澡人人爽欧美一区 | 无码福利日韩神码福利片 | 亚洲综合色区中文字幕 | 男人和女人高潮免费网站 | 午夜熟女插插xx免费视频 | 久久久婷婷五月亚洲97号色 | 草草网站影院白丝内射 | 狠狠cao日日穞夜夜穞av | 国产精品高潮呻吟av久久4虎 | 亚洲中文字幕无码中文字在线 | 蜜桃臀无码内射一区二区三区 | 亚洲欧美中文字幕5发布 | 精品国偷自产在线 | 亚洲中文字幕无码中字 | 久久视频在线观看精品 | 中文字幕精品av一区二区五区 | 日本一卡二卡不卡视频查询 | 成熟女人特级毛片www免费 | 久久久www成人免费毛片 | 免费国产成人高清在线观看网站 | 亚洲成av人在线观看网址 | 人妻少妇精品无码专区动漫 | 精品成在人线av无码免费看 | 无码帝国www无码专区色综合 | 精品国产乱码久久久久乱码 | 无码免费一区二区三区 | 真人与拘做受免费视频 | 国产一区二区不卡老阿姨 | 国产乱人伦偷精品视频 | 天下第一社区视频www日本 | 秋霞成人午夜鲁丝一区二区三区 | 77777熟女视频在线观看 а天堂中文在线官网 | 对白脏话肉麻粗话av | 久久无码中文字幕免费影院蜜桃 | 色 综合 欧美 亚洲 国产 | 无码av免费一区二区三区试看 | 精品国产一区二区三区四区在线看 | 精品无码一区二区三区的天堂 | 国产精品人人妻人人爽 | 青草青草久热国产精品 | 精品一区二区不卡无码av | 在线看片无码永久免费视频 | a在线观看免费网站大全 | 色一情一乱一伦一区二区三欧美 | 国产综合在线观看 | 久久精品国产99久久6动漫 | 成人片黄网站色大片免费观看 | 熟妇女人妻丰满少妇中文字幕 | 99久久亚洲精品无码毛片 | 亚洲精品欧美二区三区中文字幕 | 亚洲爆乳大丰满无码专区 | 中文字幕无码av波多野吉衣 | 六十路熟妇乱子伦 | 无码国内精品人妻少妇 | 色老头在线一区二区三区 | 77777熟女视频在线观看 а天堂中文在线官网 | 国产精品无套呻吟在线 | 十八禁视频网站在线观看 | 日本一区二区三区免费高清 | 久久久久亚洲精品中文字幕 | 日韩人妻无码中文字幕视频 | 国产av剧情md精品麻豆 | 亚洲中文字幕久久无码 | 国产精品久久久一区二区三区 | 人人澡人人妻人人爽人人蜜桃 | 无码免费一区二区三区 | 久久亚洲精品成人无码 | 免费人成在线视频无码 | 沈阳熟女露脸对白视频 | 国产特级毛片aaaaaa高潮流水 | 高潮喷水的毛片 | 秋霞特色aa大片 | 一本精品99久久精品77 | 国产av一区二区精品久久凹凸 | 亚洲成a人片在线观看无码3d | 日本一卡2卡3卡四卡精品网站 | 人人澡人人妻人人爽人人蜜桃 | 亚洲人成影院在线无码按摩店 | 亚洲一区二区三区在线观看网站 | www国产精品内射老师 | 一本久久a久久精品亚洲 | 午夜免费福利小电影 | 亚洲日韩一区二区三区 | 国产另类ts人妖一区二区 | 无码成人精品区在线观看 | 天天摸天天碰天天添 | 欧美人与禽猛交狂配 | 狠狠色噜噜狠狠狠狠7777米奇 | 国产香蕉尹人视频在线 | √天堂资源地址中文在线 | 国产精品久久久久7777 | 久久久中文字幕日本无吗 | 欧美三级不卡在线观看 | 久激情内射婷内射蜜桃人妖 | 18精品久久久无码午夜福利 | 国产精品国产三级国产专播 | 秋霞成人午夜鲁丝一区二区三区 | 亚洲自偷自偷在线制服 | 2020最新国产自产精品 | 精品乱码久久久久久久 | 成人免费视频视频在线观看 免费 | 国产激情艳情在线看视频 | 国内丰满熟女出轨videos | 六月丁香婷婷色狠狠久久 | 久久久亚洲欧洲日产国码αv | 丰满人妻一区二区三区免费视频 | 国内精品人妻无码久久久影院蜜桃 | 久久精品人人做人人综合 | 亚洲中文字幕无码中字 | 欧美性生交活xxxxxdddd | 丰腴饱满的极品熟妇 | 蜜桃av抽搐高潮一区二区 | 午夜福利试看120秒体验区 | 欧美日韩一区二区综合 | 久久精品中文字幕一区 | 国产做国产爱免费视频 | 国产一区二区三区四区五区加勒比 | 亚洲成a人片在线观看无码3d | 欧美 日韩 人妻 高清 中文 | 婷婷五月综合激情中文字幕 | 欧美一区二区三区 | 国产精品久久久久无码av色戒 | 久久天天躁夜夜躁狠狠 | 在线观看欧美一区二区三区 | 国产欧美亚洲精品a | 欧美 亚洲 国产 另类 | 人妻与老人中文字幕 | 精品 日韩 国产 欧美 视频 | 亚洲aⅴ无码成人网站国产app | 国产精品人妻一区二区三区四 | 日日天干夜夜狠狠爱 | 成人一在线视频日韩国产 | 久久 国产 尿 小便 嘘嘘 | 久久无码人妻影院 | 欧美放荡的少妇 | 无码国内精品人妻少妇 | 综合激情五月综合激情五月激情1 | 久久久久成人精品免费播放动漫 | 欧美丰满少妇xxxx性 | 一本久久伊人热热精品中文字幕 | 国产农村妇女高潮大叫 | 99精品国产综合久久久久五月天 | 国产精华av午夜在线观看 | 天堂а√在线中文在线 | 亚洲成av人综合在线观看 | 午夜福利不卡在线视频 | 精品亚洲韩国一区二区三区 | 狠狠cao日日穞夜夜穞av | 久久国产精品偷任你爽任你 | 天堂亚洲免费视频 | 日本精品人妻无码77777 天堂一区人妻无码 | 精品欧美一区二区三区久久久 | 天天拍夜夜添久久精品大 | 久久久国产一区二区三区 | 夜夜夜高潮夜夜爽夜夜爰爰 | 夜精品a片一区二区三区无码白浆 | 精品欧美一区二区三区久久久 | 亚洲欧美日韩综合久久久 | 亚洲精品久久久久久一区二区 | 亚洲色欲色欲天天天www | 亚洲精品综合五月久久小说 | 久久综合九色综合97网 | 午夜精品一区二区三区的区别 | 少妇人妻偷人精品无码视频 | 377p欧洲日本亚洲大胆 | 国产成人无码av一区二区 | 国产精品国产三级国产专播 | 日日麻批免费40分钟无码 | 亚洲国产精品成人久久蜜臀 | а√资源新版在线天堂 | 日韩少妇白浆无码系列 | 亚洲精品无码人妻无码 | 国产精品亚洲а∨无码播放麻豆 | 亚洲综合无码久久精品综合 | 久久综合给久久狠狠97色 | 成人免费视频在线观看 | 国产 浪潮av性色四虎 | 麻豆精品国产精华精华液好用吗 | 东京热一精品无码av | 国产精品久久久久9999小说 | 亚洲精品鲁一鲁一区二区三区 | 国产精品资源一区二区 | 老熟妇仑乱视频一区二区 | 精品无码av一区二区三区 | 欧美高清在线精品一区 | 精品熟女少妇av免费观看 | 高潮毛片无遮挡高清免费 | 欧美 日韩 人妻 高清 中文 | 精品一区二区三区波多野结衣 | 草草网站影院白丝内射 | 国产精品久久久久久无码 | 毛片内射-百度 | 偷窥日本少妇撒尿chinese | 久久午夜无码鲁丝片 | 国产国语老龄妇女a片 | 成人欧美一区二区三区 | 国产高清不卡无码视频 | 精品久久综合1区2区3区激情 | 国内综合精品午夜久久资源 | 内射巨臀欧美在线视频 | 国产精品人人爽人人做我的可爱 | a在线观看免费网站大全 | 免费观看激色视频网站 | 色一情一乱一伦一视频免费看 | 欧美精品无码一区二区三区 | 在线欧美精品一区二区三区 | 国产免费久久精品国产传媒 | 午夜嘿嘿嘿影院 | 国产人妻久久精品二区三区老狼 | 麻豆av传媒蜜桃天美传媒 | 亚洲一区二区观看播放 | 亚洲中文字幕成人无码 | 久久精品女人天堂av免费观看 | 国产亚洲人成在线播放 | 人妻插b视频一区二区三区 | a片免费视频在线观看 | 5858s亚洲色大成网站www | 无码中文字幕色专区 | 国产亚洲欧美日韩亚洲中文色 | 真人与拘做受免费视频 | 精品夜夜澡人妻无码av蜜桃 | 荫蒂添的好舒服视频囗交 | 97人妻精品一区二区三区 | 午夜精品久久久久久久 | 亚洲va欧美va天堂v国产综合 | 水蜜桃亚洲一二三四在线 | 亚洲精品美女久久久久久久 | 老熟女乱子伦 | www国产亚洲精品久久久日本 | 国产xxx69麻豆国语对白 | 欧美真人作爱免费视频 | 亚洲狠狠婷婷综合久久 | 永久免费精品精品永久-夜色 | 国精产品一区二区三区 | 亚洲色欲色欲天天天www | 亚洲中文字幕无码中文字在线 | 97人妻精品一区二区三区 | 97久久国产亚洲精品超碰热 | 一本久道久久综合狠狠爱 | 沈阳熟女露脸对白视频 | 亚洲の无码国产の无码影院 | 一本色道婷婷久久欧美 | 成人动漫在线观看 | 久久zyz资源站无码中文动漫 | 欧美日韩一区二区三区自拍 | 好爽又高潮了毛片免费下载 | 天天摸天天透天天添 | 精品成在人线av无码免费看 | 天干天干啦夜天干天2017 | 久久精品国产日本波多野结衣 | 国产精品亚洲一区二区三区喷水 | 亚洲综合无码一区二区三区 | 成人欧美一区二区三区 | 国产激情精品一区二区三区 | 双乳奶水饱满少妇呻吟 | 18禁黄网站男男禁片免费观看 | 在线观看国产午夜福利片 | 波多野结衣高清一区二区三区 | 波多野结衣高清一区二区三区 | 又色又爽又黄的美女裸体网站 | 国产网红无码精品视频 | 久久人人97超碰a片精品 | 日本一区二区更新不卡 | 东京热无码av男人的天堂 | 老太婆性杂交欧美肥老太 | 麻豆人妻少妇精品无码专区 | 国产成人综合色在线观看网站 | 台湾无码一区二区 | 131美女爱做视频 | 国产人妻精品午夜福利免费 | 亚洲aⅴ无码成人网站国产app | 2020久久超碰国产精品最新 | 强开小婷嫩苞又嫩又紧视频 | 免费观看又污又黄的网站 | 久久久久亚洲精品男人的天堂 | 无码任你躁久久久久久久 | 国产 精品 自在自线 | 欧美亚洲国产一区二区三区 | ass日本丰满熟妇pics | 国产深夜福利视频在线 | 精品成在人线av无码免费看 | 人人妻人人澡人人爽人人精品浪潮 | 三上悠亚人妻中文字幕在线 | 高潮毛片无遮挡高清免费 | 波多野结衣高清一区二区三区 | 久久综合狠狠综合久久综合88 | 欧美老妇与禽交 | 大屁股大乳丰满人妻 | 国产美女极度色诱视频www | 男女性色大片免费网站 | 夜精品a片一区二区三区无码白浆 | 蜜臀aⅴ国产精品久久久国产老师 | 精品一区二区三区无码免费视频 | 伊人久久大香线焦av综合影院 | 亚洲人交乣女bbw | 欧美性猛交xxxx富婆 | 国产乱人伦av在线无码 | 亚洲欧美日韩国产精品一区二区 | 国产人妻精品午夜福利免费 | 中文字幕精品av一区二区五区 | 欧美日韩一区二区综合 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 色偷偷人人澡人人爽人人模 | a片免费视频在线观看 | 人妻天天爽夜夜爽一区二区 | 欧美黑人巨大xxxxx | 精品无码国产一区二区三区av | 少妇性l交大片 | 午夜无码人妻av大片色欲 | 熟妇人妻激情偷爽文 | 我要看www免费看插插视频 | aⅴ在线视频男人的天堂 | 一本精品99久久精品77 | 国产精品亚洲综合色区韩国 | 亚洲精品美女久久久久久久 | √8天堂资源地址中文在线 | 高潮毛片无遮挡高清免费视频 | 国产成人综合色在线观看网站 | 丰满护士巨好爽好大乳 | 欧美老妇交乱视频在线观看 | 无码人妻黑人中文字幕 | 日本成熟视频免费视频 | 欧美黑人巨大xxxxx | 久久综合九色综合欧美狠狠 | 又色又爽又黄的美女裸体网站 | 内射白嫩少妇超碰 | 精品无码国产一区二区三区av | 国产精品国产三级国产专播 | 亚洲成a人片在线观看无码3d | 欧美高清在线精品一区 | 久久久久久久人妻无码中文字幕爆 | 成人精品视频一区二区三区尤物 | 人妻插b视频一区二区三区 | 久久无码人妻影院 | 在线а√天堂中文官网 | 好爽又高潮了毛片免费下载 | 亚洲一区二区三区香蕉 | 亚洲国产精品美女久久久久 | 在线成人www免费观看视频 | 国产精品欧美成人 | 亚洲 日韩 欧美 成人 在线观看 | 国产精品内射视频免费 | 三上悠亚人妻中文字幕在线 | 无码av最新清无码专区吞精 | 国产精品第一国产精品 | 女人被男人躁得好爽免费视频 | 无码av岛国片在线播放 | 国产又爽又黄又刺激的视频 | 扒开双腿疯狂进出爽爽爽视频 | 久久人人爽人人人人片 | 自拍偷自拍亚洲精品被多人伦好爽 | 国产乱人无码伦av在线a | 久久婷婷五月综合色国产香蕉 | 亚洲国产成人av在线观看 | 欧洲熟妇精品视频 | 真人与拘做受免费视频 | 色综合视频一区二区三区 | 国产亚洲精品久久久闺蜜 | 黑人玩弄人妻中文在线 | 双乳奶水饱满少妇呻吟 | 东北女人啪啪对白 | 婷婷丁香五月天综合东京热 | 免费人成在线视频无码 | 亚洲熟妇色xxxxx欧美老妇 | 日韩精品无码一区二区中文字幕 | 无套内射视频囯产 | 亚洲欧美综合区丁香五月小说 | 国内揄拍国内精品少妇国语 | 麻豆人妻少妇精品无码专区 | 东京热一精品无码av | 波多野结衣aⅴ在线 | 亚洲精品久久久久中文第一幕 | √天堂资源地址中文在线 | 亚无码乱人伦一区二区 | 骚片av蜜桃精品一区 | 少妇被黑人到高潮喷出白浆 | 亚洲成在人网站无码天堂 | 国产熟妇另类久久久久 | 精品无码av一区二区三区 | 性色欲网站人妻丰满中文久久不卡 | 高清国产亚洲精品自在久久 | 精品无码一区二区三区的天堂 | aⅴ在线视频男人的天堂 | 久久久久久久女国产乱让韩 | 精品国产成人一区二区三区 | 国产在线精品一区二区高清不卡 | 亚洲精品国产品国语在线观看 | 国产精品二区一区二区aⅴ污介绍 | 思思久久99热只有频精品66 | 99久久亚洲精品无码毛片 | av在线亚洲欧洲日产一区二区 | 国产精品亚洲一区二区三区喷水 | 久久成人a毛片免费观看网站 | 亚洲中文字幕乱码av波多ji | 99riav国产精品视频 | 日本熟妇人妻xxxxx人hd | 精品国产一区av天美传媒 | 国产成人无码一二三区视频 | 久久午夜夜伦鲁鲁片无码免费 | 熟妇人妻中文av无码 | 国产精品第一国产精品 | 久久久久亚洲精品男人的天堂 | 国产小呦泬泬99精品 | 曰本女人与公拘交酡免费视频 | 中国女人内谢69xxxx | 老子影院午夜伦不卡 | 精品无码av一区二区三区 | 丰满少妇弄高潮了www | 免费观看激色视频网站 | 少妇无套内谢久久久久 | 午夜无码区在线观看 | 国产亚洲精品久久久ai换 | 国产精品人妻一区二区三区四 | 日本一区二区更新不卡 | 东京无码熟妇人妻av在线网址 | 人人爽人人澡人人人妻 | 九九在线中文字幕无码 | 麻豆精品国产精华精华液好用吗 | 国产精品丝袜黑色高跟鞋 | 中文字幕av日韩精品一区二区 | 国产综合久久久久鬼色 | 老子影院午夜伦不卡 | 欧美日韩亚洲国产精品 | 300部国产真实乱 | 无码一区二区三区在线观看 | 一本一道久久综合久久 | 精品人人妻人人澡人人爽人人 | 女人被男人爽到呻吟的视频 | 男人的天堂av网站 | 美女张开腿让人桶 | 精品一二三区久久aaa片 | 98国产精品综合一区二区三区 | 国产亚洲精品久久久久久大师 | 狠狠cao日日穞夜夜穞av | 亚洲精品国产品国语在线观看 | 日本一区二区三区免费高清 | 国产片av国语在线观看 | 成人精品视频一区二区三区尤物 | 亚洲国产一区二区三区在线观看 | 成人精品视频一区二区 | 免费观看激色视频网站 | 人妻少妇被猛烈进入中文字幕 | 日韩人妻无码一区二区三区久久99 | 亚洲最大成人网站 | 麻豆人妻少妇精品无码专区 | 亚洲人交乣女bbw | 日韩欧美中文字幕在线三区 | 欧美一区二区三区视频在线观看 | 熟妇人妻无码xxx视频 | 久久午夜无码鲁丝片秋霞 | 日日橹狠狠爱欧美视频 | 国产真实乱对白精彩久久 | 中文字幕日韩精品一区二区三区 | 日本大香伊一区二区三区 | 久久www免费人成人片 | 黄网在线观看免费网站 | 国产超碰人人爽人人做人人添 | 性欧美熟妇videofreesex | 欧美日韩一区二区三区自拍 | 无码人妻丰满熟妇区五十路百度 | 久久久久免费看成人影片 | 亚洲国产精品美女久久久久 | 无码av岛国片在线播放 | 欧美成人免费全部网站 | 久久国语露脸国产精品电影 | 久久视频在线观看精品 | 美女黄网站人色视频免费国产 | 精品无码一区二区三区爱欲 | 无人区乱码一区二区三区 | 骚片av蜜桃精品一区 | 成熟人妻av无码专区 | a在线观看免费网站大全 | 亚洲色欲色欲天天天www | 人人澡人人妻人人爽人人蜜桃 | 东京一本一道一二三区 | 久久这里只有精品视频9 | 76少妇精品导航 | 成人精品一区二区三区中文字幕 | 久久99久久99精品中文字幕 | 国语自产偷拍精品视频偷 | 久久久久se色偷偷亚洲精品av | 国产精品视频免费播放 | 澳门永久av免费网站 | 色综合久久88色综合天天 | 中文无码精品a∨在线观看不卡 | 欧美高清在线精品一区 | 日韩精品成人一区二区三区 | 国产av剧情md精品麻豆 | 亚洲经典千人经典日产 | 久久国产精品_国产精品 | 亚洲の无码国产の无码步美 | 中文字幕乱码人妻无码久久 | 欧美黑人巨大xxxxx | 未满成年国产在线观看 | 狂野欧美激情性xxxx | 中文字幕中文有码在线 | 国产精品无码永久免费888 | 亚洲中文字幕无码中字 | 亚洲中文无码av永久不收费 | 伊在人天堂亚洲香蕉精品区 | 天干天干啦夜天干天2017 | 国产精品99爱免费视频 | 国产在线精品一区二区三区直播 | 美女毛片一区二区三区四区 | 青青青手机频在线观看 | 国产精品鲁鲁鲁 | 精品久久久久久人妻无码中文字幕 | a国产一区二区免费入口 | 麻花豆传媒剧国产免费mv在线 | 水蜜桃av无码 | 女人被男人躁得好爽免费视频 | 久久综合给合久久狠狠狠97色 | 亲嘴扒胸摸屁股激烈网站 | 熟女少妇人妻中文字幕 | 国产亚洲人成a在线v网站 | 77777熟女视频在线观看 а天堂中文在线官网 | 日韩人妻少妇一区二区三区 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲区欧美区综合区自拍区 | 午夜福利电影 | 国内揄拍国内精品人妻 | 一本色道久久综合亚洲精品不卡 | 成年美女黄网站色大免费视频 | 日韩欧美群交p片內射中文 | 国产人妻精品午夜福利免费 | 欧美zoozzooz性欧美 | 国内精品九九久久久精品 | 国产 精品 自在自线 | 日韩人妻无码一区二区三区久久99 | 日本欧美一区二区三区乱码 | 国产卡一卡二卡三 | 黑人巨大精品欧美黑寡妇 | 亚洲精品久久久久avwww潮水 | 午夜肉伦伦影院 | 大乳丰满人妻中文字幕日本 | 永久免费观看美女裸体的网站 | 色婷婷香蕉在线一区二区 | 一本久久a久久精品亚洲 | 熟女体下毛毛黑森林 | 国产精品第一国产精品 | 中文字幕人妻无码一夲道 | 亚洲国产精品久久人人爱 | 夜夜夜高潮夜夜爽夜夜爰爰 | 无遮无挡爽爽免费视频 | 欧美刺激性大交 | 88国产精品欧美一区二区三区 | 久久99精品国产麻豆 | 在线观看欧美一区二区三区 | 在线 国产 欧美 亚洲 天堂 | 少妇久久久久久人妻无码 | 成人精品天堂一区二区三区 | 欧美 亚洲 国产 另类 | 亚洲精品午夜无码电影网 | 久久精品国产日本波多野结衣 | 亚洲综合精品香蕉久久网 | 无码人妻少妇伦在线电影 | 日韩精品久久久肉伦网站 | 人妻aⅴ无码一区二区三区 | 图片小说视频一区二区 | 综合激情五月综合激情五月激情1 | 国产又粗又硬又大爽黄老大爷视 | 精品无人国产偷自产在线 | 久久久久久久久蜜桃 | 国产成人av免费观看 | 天天拍夜夜添久久精品大 | 午夜理论片yy44880影院 | 熟妇女人妻丰满少妇中文字幕 | 久久亚洲精品中文字幕无男同 | 天堂а√在线地址中文在线 | 国产肉丝袜在线观看 | 成人无码精品1区2区3区免费看 | 中文字幕日韩精品一区二区三区 | 精品国产麻豆免费人成网站 | 丰满人妻翻云覆雨呻吟视频 | 免费无码av一区二区 | 亚洲欧美色中文字幕在线 | 成人一区二区免费视频 | 嫩b人妻精品一区二区三区 | 丰满诱人的人妻3 | 无码av免费一区二区三区试看 | 国产精品第一国产精品 | 一本久道久久综合婷婷五月 | 99re在线播放 | 美女张开腿让人桶 | 国产精品国产三级国产专播 | 一本色道婷婷久久欧美 | 99久久久无码国产aaa精品 | 图片区 小说区 区 亚洲五月 | 香港三级日本三级妇三级 | 日韩少妇内射免费播放 | 激情爆乳一区二区三区 | 久久精品国产99精品亚洲 | 日韩亚洲欧美中文高清在线 | 国产精品-区区久久久狼 | 激情国产av做激情国产爱 | 色一情一乱一伦一视频免费看 | 福利一区二区三区视频在线观看 | 又大又紧又粉嫩18p少妇 | 午夜精品久久久久久久 | 国产在线aaa片一区二区99 | 少妇邻居内射在线 | 亚洲成av人片天堂网无码】 | 日本成熟视频免费视频 | 无遮无挡爽爽免费视频 | 2019午夜福利不卡片在线 | 国产精品福利视频导航 | 亚洲精品无码国产 | 奇米影视888欧美在线观看 | 国产亚洲精品久久久ai换 | 99久久久无码国产精品免费 | 国产人妻精品一区二区三区不卡 | 国产精品a成v人在线播放 | √天堂中文官网8在线 | 色综合久久久久综合一本到桃花网 | 国产精华av午夜在线观看 | 久久婷婷五月综合色国产香蕉 | 无码精品人妻一区二区三区av | 131美女爱做视频 | 国产深夜福利视频在线 | 亚洲色www成人永久网址 | 未满成年国产在线观看 | 国产亚洲精品久久久久久国模美 | 免费无码一区二区三区蜜桃大 | 内射爽无广熟女亚洲 | 国产一区二区三区四区五区加勒比 | 牲欲强的熟妇农村老妇女 | 波多野42部无码喷潮在线 | 人人澡人摸人人添 | 国产国产精品人在线视 | 少妇无码一区二区二三区 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产成人亚洲综合无码 | 亚洲熟妇自偷自拍另类 | 高潮毛片无遮挡高清免费 | 丰满妇女强制高潮18xxxx | 国产精品视频免费播放 | 中文字幕人成乱码熟女app | 国产亚洲精品久久久闺蜜 | 欧美日韩视频无码一区二区三 | 粗大的内捧猛烈进出视频 | 强开小婷嫩苞又嫩又紧视频 | 亚洲爆乳精品无码一区二区三区 | 国产精品成人av在线观看 | 欧美乱妇无乱码大黄a片 | 国产香蕉97碰碰久久人人 | 亚洲热妇无码av在线播放 | 久久综合给久久狠狠97色 | 欧美国产日产一区二区 | 国产精品人人妻人人爽 | 丁香啪啪综合成人亚洲 | 亚洲最大成人网站 | 久久精品无码一区二区三区 | 精品久久久久香蕉网 | 伊人久久大香线蕉亚洲 | 风流少妇按摩来高潮 | 国产成人午夜福利在线播放 | 欧美野外疯狂做受xxxx高潮 | 精品国偷自产在线视频 | 国产亚洲精品久久久久久久久动漫 | 性色欲情网站iwww九文堂 | 一个人免费观看的www视频 | 中文字幕人成乱码熟女app | 国产av一区二区精品久久凹凸 | 亚洲国产精品成人久久蜜臀 | 成人一在线视频日韩国产 | 99国产精品白浆在线观看免费 | 又大又硬又黄的免费视频 | 国产97人人超碰caoprom | 国产精品二区一区二区aⅴ污介绍 | 亚洲精品午夜国产va久久成人 | 亚洲精品综合五月久久小说 | 乱码午夜-极国产极内射 | 久久综合香蕉国产蜜臀av | 国产黄在线观看免费观看不卡 | 亚洲国产高清在线观看视频 | 伊人久久大香线蕉亚洲 | 日韩精品无码一区二区中文字幕 | 久久国产精品萌白酱免费 | 成年美女黄网站色大免费全看 | 一本久久伊人热热精品中文字幕 | 久久伊人色av天堂九九小黄鸭 | 狂野欧美激情性xxxx | 亚洲中文字幕成人无码 | 欧美丰满少妇xxxx性 | 国产高清av在线播放 | 亚洲国产精品无码一区二区三区 | 牲欲强的熟妇农村老妇女视频 | 人妻aⅴ无码一区二区三区 | 国内精品九九久久久精品 | 成人亚洲精品久久久久软件 | 国产特级毛片aaaaaaa高清 | 高潮喷水的毛片 | 丰满人妻一区二区三区免费视频 | 亚洲综合色区中文字幕 | 风流少妇按摩来高潮 | 国模大胆一区二区三区 | 国产综合色产在线精品 | 乱码av麻豆丝袜熟女系列 | 国内揄拍国内精品人妻 | 精品无码国产自产拍在线观看蜜 | 国产精品久久久久久亚洲毛片 | 亚洲精品国偷拍自产在线麻豆 | 又紧又大又爽精品一区二区 | 国产成人无码一二三区视频 | 日本熟妇浓毛 | 亚洲性无码av中文字幕 | 久久综合久久自在自线精品自 | 国产精品国产自线拍免费软件 | 少妇的肉体aa片免费 | 久久精品中文字幕大胸 | 伊人久久大香线蕉亚洲 | 国产69精品久久久久app下载 | 免费视频欧美无人区码 | 日韩精品a片一区二区三区妖精 | 精品偷自拍另类在线观看 | 国产午夜无码视频在线观看 | 伊人久久婷婷五月综合97色 | 性欧美牲交xxxxx视频 | 男人扒开女人内裤强吻桶进去 | 欧美国产日韩久久mv | 国产莉萝无码av在线播放 | 久久精品视频在线看15 | 精品国产av色一区二区深夜久久 | 欧美喷潮久久久xxxxx | 午夜嘿嘿嘿影院 | 国产成人无码一二三区视频 | 纯爱无遮挡h肉动漫在线播放 | 国产黄在线观看免费观看不卡 | 偷窥村妇洗澡毛毛多 | 三级4级全黄60分钟 | 国产精品99久久精品爆乳 | 亚洲阿v天堂在线 | 亚洲国产精品一区二区第一页 | 亚洲自偷精品视频自拍 | 无码人妻丰满熟妇区五十路百度 | 狠狠色丁香久久婷婷综合五月 | 青春草在线视频免费观看 | 亚洲精品午夜无码电影网 | 精品久久久无码人妻字幂 | 日本精品少妇一区二区三区 | 婷婷五月综合缴情在线视频 | 老子影院午夜精品无码 | 午夜福利不卡在线视频 | 国产在热线精品视频 | 天天综合网天天综合色 | 人妻少妇精品久久 | 奇米影视888欧美在线观看 | 人妻中文无码久热丝袜 | 欧美国产日韩亚洲中文 | 成年美女黄网站色大免费视频 | 久久久久se色偷偷亚洲精品av | 亚洲中文字幕久久无码 | 国产香蕉97碰碰久久人人 | 欧洲精品码一区二区三区免费看 | 亚洲人亚洲人成电影网站色 | 精品少妇爆乳无码av无码专区 | 2019午夜福利不卡片在线 | 少妇高潮一区二区三区99 | 欧美黑人巨大xxxxx | 亚洲呦女专区 | 亚洲欧美综合区丁香五月小说 | 小泽玛莉亚一区二区视频在线 | 啦啦啦www在线观看免费视频 | 国产精品无码永久免费888 | 乱码午夜-极国产极内射 | 蜜桃av抽搐高潮一区二区 | 日日摸夜夜摸狠狠摸婷婷 | 无码帝国www无码专区色综合 | 国产在线一区二区三区四区五区 | 久久国产36精品色熟妇 | 国产精品二区一区二区aⅴ污介绍 | 窝窝午夜理论片影院 | 国产免费久久久久久无码 | 亚洲无人区一区二区三区 | 天下第一社区视频www日本 | 精品久久久中文字幕人妻 | 四虎永久在线精品免费网址 | 午夜精品久久久久久久 | 红桃av一区二区三区在线无码av | 夜夜夜高潮夜夜爽夜夜爰爰 | 精品无码国产自产拍在线观看蜜 | 久久国产劲爆∧v内射 | 国产精品久久精品三级 | 国产亚洲日韩欧美另类第八页 |