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

初步研究node中的網絡通信模塊

網絡 通信技術
目前,我們處于互聯網時代,互聯網產品百花齊放。例如,當打開瀏覽器,可以看到各種信息,瀏覽器是如何跟服務器進行通信的?當打開微信跟朋友聊天時,你是如何跟朋友進行消息傳遞的?這些都得靠網絡進程之間的通信,都得依賴于socket。那什么是socket?node中有哪些跟網絡通信有關的模塊?這些問題是本文研究的重點。

目前,我們處于互聯網時代,互聯網產品百花齊放。例如,當打開瀏覽器,可以看到各種信息,瀏覽器是如何跟服務器進行通信的?當打開微信跟朋友聊天時,你是如何跟朋友進行消息傳遞的?這些都得靠網絡進程之間的通信,都得依賴于socket。那什么是socket?node中有哪些跟網絡通信有關的模塊?這些問題是本文研究的重點。

1. Socket

Socket源于Unix,而Unix的基本哲學是『一些皆文件』,都可以用『打開open ==> 讀/寫(read/write) ==> 關閉(close)』模式來操作,Socket也可以采用這種方法進行理解。關于Socket,可以總結如下幾點:

  • 可以實現底層通信,幾乎所有的應用層都是通過socket進行通信的,因此『一切且socket』
  • 對TCP/IP協議進行封裝,便于應用層協議調用,屬于二者之間的中間抽象層
  • 各個語言都與相關實現,例如C、C++、node
  • TCP/IP協議族中,傳輸層存在兩種通用協議: TCP、UDP,兩種協議不同,因為不同參數的socket實現過程也不一樣

初步研究node中的網絡通信模塊

2. node中網絡通信的架構實現

node中的模塊,從兩種語言實現角度來說,存在javscript、c++兩部分,通過 process.binding 來建立關系。具體分析如下:

  • 標準的node模塊有net、udp、dns、http、tls、https等
  • V8是chrome的內核,提供了javascript解釋運行功能,里面包含tcp_wrap.h、udp_wrap.h、tls_wrap.h等
  • OpenSSL是基本的密碼庫,包括了MD5、SHA1、RSA等加密算法,構成了node標準模塊中的 crypto
  • cares模塊用于DNS的解析
  • libuv實現了跨平臺的異步編程
  • http_parser用于http的解析

初步研究node中的網絡通信模塊

3. net使用

net模塊 是基于TCP協議的socket網路編程模塊,http模塊就是建立在該模塊的基礎上實現的,先來看看基本使用方法:

  1. // 創建socket服務器 server.js  
  2. const net = require('net' 
  3. const server = net.createServer();  
  4. server.on('connection', (socket) => {  
  5. socket.pipe(process.stdout);  
  6. socket.write('data from server');  
  7. });  
  8. server.listen(3000, () => {  
  9. console.log(`server is on ${JSON.stringify(server.address())}`);  
  10. });  
  11. // 創建socket客戶端 client.js  
  12. const net = require('net');  
  13. const client = net.connect({port: 3000});  
  14. client.on('connect', () => {  
  15. client.write('data from client');  
  16. });  
  17. client.on('data', (chunk) => {  
  18. console.log(chunk.toString());  
  19. client.end();  
  20. });  
  21. // 打開兩個終端,分別執行`node server.js`、`node client.js`,可以看到客戶端與服務器進行了數據通信。 

使用 const server = net.createServer(); 創建了server對象,那server對象有哪些特點:

  1. // net.js  
  2. exports.createServer = function(options, connectionListener) {  
  3. return new Server(options, connectionListener);  
  4. }; 
  5. function Server(options, connectionListener) {  
  6. EventEmitter.call(this);  
  7. ...  
  8. if (typeof connectionListener === 'function') {  
  9. this.on('connection', connectionListener);  
  10.  
  11. ...  
  12. this._handle = null 
  13.  
  14. util.inherits(Server, EventEmitter); 

上述代碼可以分為幾個點:

  • createServer 就是一個語法糖,幫助new生成server對象
  • server對象繼承了EventEmitter,具有事件的相關方法
  • _handle是server處理的句柄,屬性值最終由c++部分的 TCP 、 Pipe 類創建
  • connectionListener也是語法糖,作為connection事件的回調函數

再來看看connectionListener事件的回調函數,里面包含一個 socket 對象,該對象是一個連接套接字,是個五元組(server_host、server_ip、protocol、client_host、client_ip),相關實現如下:

  1. function onconnection(err, clientHandle) {  
  2. ...  
  3. var socket = new Socket({
  4. ...  
  5. });  
  6. ...  
  7. self.emit('connection', socket);  

因為Socket是繼承了 stream.Duplex ,所以Socket也是一個可讀可寫流,可以使用流的方法進行數據的處理。

接下來就是很關鍵的端口監聽(port),這是server與client的主要區別,代碼:

  1. Server.prototype.listen = function() {  
  2. ...  
  3. listen(self, ip, port, addressType, backlog, fd, exclusive);  
  4. ...  
  5.  
  6. function listen(self, address, port, addressType, backlog, fd, exclusive) {  
  7. ...  
  8. if (!cluster) cluster = require('cluster');  
  9. if (cluster.isMaster || exclusive) {  
  10. self._listen2(address, port, addressType, backlog, fd);  
  11. return 
  12.  
  13. cluster._getServer(self, {  
  14. ...  
  15. }, cb);  
  16. function cb(err, handle) { 
  17. ...  
  18. self._handle = handle;  
  19. self._listen2(address, port, addressType, backlog, fd);  
  20. ...  
  21.  
  22.  
  23. Server.prototype._listen2 = function(address, port, addressType, backlog, fd) {  
  24. if (this._handle) {  
  25. ...  
  26. else {  
  27. ...  
  28. rval = createServerHandle(address, port, addressType, fd);  
  29. ...  
  30. this._handle = rval;  
  31.  
  32. this._handle.onconnection = onconnection;  
  33. var err = _listen(this._handle, backlog);  
  34. ...  
  35.  
  36. function _listen(handle, backlog) {  
  37. return handle.listen(backlog || 511);  

上述代碼有幾個點需要注意:

  • 監聽的對象可以是端口、路徑、定義好的server句柄、文件描述符
  • 當通過cluster創建工作進程(worker)時,exclusive判斷是否進行socket連接的共享
  • 事件監聽最終還是通過TCP/Pipe的listen來實現
  • backlog規定了socket連接的限制,默認最多為511

接下來分析下listen中最重要的 _handle 了,_handle決定了server的功能:

  1. function createServerHandle(address, port, addressType, fd) {  
  2. ...  
  3. if (typeof fd === 'number' && fd >= 0) {  
  4. ...  
  5. handle = createHandle(fd);  
  6. ...  
  7. else if(port === -1 && addressType === -1){  
  8. handle = new Pipe();  
  9. else {  
  10. handle = new TCP();
  11.  
  12. ...  
  13. return handle;  
  14.  
  15. function createHandle(fd) {  
  16. var type = TTYWrap.guessHandleType(fd);  
  17. if (type === 'PIPE'return new Pipe();  
  18. if (type === 'TCP'return new TCP();  
  19. throw new TypeError('Unsupported fd type: ' + type);  

_handle 由C++中的Pipe、TCP實現,因而要想完全搞清楚node中的網絡通信,必須深入到V8的源碼里面。

4. UDP/dgram使用

跟net模塊相比,基于UDP通信的dgram模塊就簡單了很多,因為不需要通過三次握手建立連接,所以整個通信的過程就簡單了很多,對于數據準確性要求不太高的業務場景,可以使用該模塊完成數據的通信。

  1. // server端實現  
  2. const dgram = require('dgram');  
  3. const server = dgram.createSocket('udp4');  
  4. server.on('message', (msg, addressInfo) => {  
  5. console.log(addressInfo);  
  6. console.log(msg.toString());  
  7. const data = Buffer.from('from server');  
  8. server.send(data, addressInfo.port);  
  9. });  
  10. server.bind(3000, () => {  
  11. console.log('server is on ', server.address());  
  12. });  
  13. // client端實現  
  14. const dgram = require('dgram');  
  15. const client = dgram.createSocket('udp4');  
  16. const data = Buffer.from('from client');  
  17. client.send(data, 3000);  
  18. client.on('message', (msg, addressInfo) => { 
  19. console.log(addressInfo);  
  20. console.log(msg.toString());  
  21. client.close(); 
  22. }); 

從源碼層面分析上述代碼的原理實現:

  1. exports.createSocket = function(type, listener) {  
  2. return new Socket(type, listener);  
  3. };  
  4. function Socket(type, listener) {  
  5. ...  
  6. var handle = newHandle(type);  
  7. this._handle = handle;  
  8. ...  
  9. this.on('message', listener);  
  10. ...  
  11.  
  12. util.inherits(Socket, EventEmitter);  
  13. const UDP = process.binding('udp_wrap').UDP;  
  14. function newHandle(type) {  
  15. if (type == 'udp4') {  
  16. const handle = new UDP();  
  17. handle.lookup = lookup4;  
  18. return handle;  
  19.  
  20. if (type == 'udp6') {  
  21. const handle = new UDP();  
  22. handle.lookup = lookup6;  
  23. handle.bind = handle.bind6;  
  24. handle.send = handle.send6;  
  25. return handle;  
  26.  
  27. ...  
  28.  
  29. Socket.prototype.bind = function(port_ /*, address, callback*/) {  
  30. ...  
  31. startListening(self);  
  32. ...  
  33.  
  34. function startListening(socket) {  
  35. socket._handle.onmessage = onMessage;  
  36. socket._handle.recvStart();  
  37. ...  
  38. function onMessage(nread, handle, buf, rinfo) {  
  39. ... 
  40. self.emit('message', buf, rinfo);  
  41. ...  
  42.  
  43. Socket.prototype.send = function(buffer, offset, length, port, address, callback) {  
  44. ...  
  45. self._handle.lookup(address, function afterDns(ex, ip) {  
  46. doSend(ex, self, ip, list, address, port, callback);  
  47. });  
  48.  
  49. const SendWrap = process.binding('udp_wrap').SendWrap;  
  50. function doSend(ex, self, ip, list, address, port, callback) {  
  51. ...  
  52. var req = new SendWrap();  
  53. ...  
  54. var err = self._handle.send(req, list, list.length, port, ip, !!callback);  
  55. ...  

上述代碼存在幾個點需要注意:

  • UDP模塊沒有繼承stream,僅僅繼承了EventEmit,后續的所有操作都是基于事件的方式
  • UDP在創建的時候需要注意ipv4和ipv6
  • UDP的_handle是由UDP類創建的
  • 通信過程中可能需要進行DNS查詢,解析出ip地址,然后再進行其他操作

5. DNS使用

DNS(Domain Name System)用于域名解析,也就是找到host對應的ip地址,在計算機網絡中,這個工作是由網絡層的ARP協議實現。在node中存在 net 模塊來完成相應功能,其中dns里面的函數分為兩類:

依賴底層操作系統實現域名解析,也就是我們日常開發中,域名的解析規則,可以回使用瀏覽器緩存、本地緩存、路由器緩存、dns服務器,該類僅有 dns.lookup

該類的dns解析,直接到nds服務器執行域名解析

  1. const dns = require('dns');  
  2. const host = 'bj.meituan.com' 
  3. dns.lookup(host, (err, address, family) => {  
  4. if (err) {  
  5. console.log(err);  
  6. return 
  7.  
  8. console.log('by net.lookup, address is: %s, family is: %s', address, family);  
  9. });  
  10. dns.resolve(host, (err, address) => {  
  11. if (err) {  
  12. console.log(err);  
  13. return 
  14.  
  15. console.log('by net.resolve, address is: %s', address);  
  16. })  
  17. // by net.resolve, address is: 103.37.152.41  
  18. // by net.lookup, address is: 103.37.152.41, family is: 4 

在這種情況下,二者解析的結果是一樣的,但是假如我們修改本地的/etc/hosts文件呢

  1. // 在/etc/host文件中,增加:  
  2. 10.10.10.0 bj.meituan.com  
  3. // 然后再執行上述文件,結果是:  
  4. by net.resolve, address is: 103.37.152.41  
  5. by net.lookup, address is: 10.10.10.0, family is: 4 

接下來分析下dns的內部實現:

  1. const cares = process.binding('cares_wrap');  
  2. const GetAddrInfoReqWrap = cares.GetAddrInfoReqWrap;  
  3. exports.lookup = function lookup(hostname, options, callback) {  
  4. ...  
  5. callback = makeAsync(callback);  
  6. ...  
  7. var req = new GetAddrInfoReqWrap();  
  8. req.callback = callback;  
  9. var err = cares.getaddrinfo(req, hostname, family, hints);  
  10. ...  
  11.  
  12. function resolver(bindingName) {  
  13. var binding = cares[bindingName];  
  14. return function query(name, callback) {  
  15. ...  
  16. callback = makeAsync(callback);  
  17. var req = new QueryReqWrap();  
  18. req.callback = callback;  
  19. var err = binding(req, name);  
  20. ...  
  21. return req;  
  22.  
  23.  
  24. var resolveMap = Object.create(null);  
  25. exports.resolve4 = resolveMap.A = resolver('queryA');  
  26. exports.resolve6 = resolveMap.AAAA = resolver('queryAaaa');  
  27. ...  
  28. exports.resolve = function(hostname, type_, callback_) {  
  29. ...  
  30. resolver = resolveMap[type_];  
  31. return resolver(hostname, callback);  
  32. ... 

上面的源碼有幾個點需要關注:

  • lookup與resolve存在差異,使用的時候需要注意
  • 不管是lookup還是resolve,均依賴于cares庫
  • 域名解析的type很多: resolve4、resolve6、resolveCname、resolveMx、resolveNs、resolveTxt、resolveSrv、resolvePtr、resolveNaptr、resolveSoa、reverse

6. HTTP使用

在WEB開發中,HTTP作為***、最重要的應用層,是每個開發人員應該熟知的基礎知識,我面試的時候必問的一塊內容。同時,大多數同學接觸node時,首先使用的恐怕就是http模塊。先來一個簡單的demo看看:

  1. const http = require('http');  
  2. const server = http.createServer();  
  3. server.on('request', (req, res) => {  
  4. res.setHeader('foo''test');  
  5. res.writeHead(200, {  
  6. 'Content-Type''text/html' 
  7. });  
  8. res.write('');  
  9. res.end(``);  
  10. });  
  11. server.listen(3000, () => {  
  12. console.log('server is on ', server.address());  
  13. var req = http.request({ host: '127.0.0.1', port: 3000});  
  14. req.on('response', (res) => {  
  15. res.on('data', (chunk) => console.log('data from server ', chunk.toString()) );  
  16. res.on('end', () => server.close() );  
  17. });  
  18. req.end();  
  19. });  
  20. // 輸出結果如下:  
  21. // server is on { address: '::', family: 'IPv6', port: 3000 }  
  22. // data from server

針對上述demo,有很多值得深究的地方,一不注意服務就掛掉了,下面根據node的 官方文檔 ,逐個進行研究。

6.1 http.Agent

因為HTTP協議是無狀態協議,每個請求均需通過三次握手建立連接進行通信,眾所周知三次握手、慢啟動算法、四次揮手等過程很消耗時間,因此HTTP1.1協議引入了keep-alive來避免頻繁的連接。那么對于tcp連接該如何管理呢?http.Agent就是做這個工作的。先看看源碼中的關鍵部分:

  1. function Agent(options) {  
  2. ...  
  3. EventEmitter.call(this);  
  4. ...  
  5. self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets;  
  6. self.maxFreeSockets = self.options.maxFreeSockets || 256;  
  7. ...  
  8. self.requests = {}; // 請求隊列  
  9. self.sockets = {}; // 正在使用的tcp連接池  
  10. self.freeSockets = {}; // 空閑的連接池  
  11. self.on('free'function(socket, options) {  
  12. ... 
  13. // requests、sockets、freeSockets的讀寫操作  
  14. self.requests[name].shift().onSocket(socket);  
  15. freeSockets.push(socket);  
  16. ...  
  17.  
  18.  
  19. Agent.defaultMaxSockets = Infinity;  
  20. util.inherits(Agent, EventEmitter);  
  21. // 關于socket的相關增刪改查操作  
  22. Agent.prototype.addRequest = function(req, options) {  
  23. ...  
  24. if (freeLen) {  
  25. var socket = this.freeSockets[name].shift();  
  26. ...  
  27. this.sockets[name].push(socket);  
  28. ...  
  29. else if (sockLen < this.maxSockets) {  
  30. ...  
  31. else {  
  32. this.requests[name].push(req);  
  33.  
  34. ...  
  35.  
  36. Agent.prototype.createSocket = function(req, options, cb) { ... }  
  37. Agent.prototype.removeSocket = function(s, options) { ... }  
  38. exports.globalAgent = new Agent(); 

上述代碼有幾個點需要注意:

  • maxSockets默認情況下,沒有tcp連接數量的上限(Infinity)
  • 連接池管理的核心是對 sockets 、 freeSockets 的增刪查
  • globalAgent會作為http.ClientRequest的默認agent

下面可以測試下agent對請求本身的限制:

  1. // req.js  
  2. const http = require('http');  
  3. const server = http.createServer();  
  4. server.on('request', (req, res) => {  
  5. var i=1;  
  6. setTimeout(() => {  
  7. res.end('ok ', i++);  
  8. }, 1000)  
  9. });  
  10. server.listen(3000, () => {  
  11. var max = 20;  
  12. for(var i=0; i  
  13. var req = http.request({ host: '127.0.0.1', port: 3000});  
  14. req.on('response', (res) => {  
  15. res.on('data', (chunk) => console.log('data from server ', chunk.toString()) );  
  16. res.on('end', () => server.close() );
  17. });  
  18. req.end();  
  19.  
  20. });  
  21. // 在終端中執行time node ./req.js,結果為:  
  22. // real 0m1.123s  
  23. // user 0m0.102s  
  24. // sys 0m0.024s  
  25. // 在req.js中添加下面代碼  
  26. http.globalAgent.maxSockets = 5; 
  27. // 然后同樣time node ./req.js,結果為:  
  28. real 0m4.141s  
  29. user 0m0.103s  
  30. sys 0m0.024s 

當設置maxSockets為某個值時,tcp的連接就會被限制在某個值,剩余的請求就會進入 requests 隊列里面,等有空余的socket連接后,從request隊列中出棧,發送請求。

6.2 http.ClientRequest

當執行http.request時,會生成ClientRequest對象,該對象雖然沒有直接繼承Stream.Writable,但是繼承了http.OutgoingMessage,而http.OutgoingMessage實現了write、end方法,因為可以當跟stream.Writable一樣的使用。

  1. var req = http.request({ host: '127.0.0.1', port: 3000, method: 'post'});  
  2. req.on('response', (res) => {  
  3. res.on('data', (chunk) => console.log('data from server ', chunk.toString()) );  
  4. res.on('end', () => server.close() );  
  5. });  
  6. // 直接使用pipe,在request請求中添加數據  
  7. fs.createReadStream('./data.json').pipe(req); 

接下來,看看http.ClientRequest的實現, ClientRequest繼承了OutgoingMessage:

  1. const OutgoingMessage = require('_http_outgoing').OutgoingMessage;  
  2. function ClientRequest(options, cb) {  
  3. ...  
  4. OutgoingMessage.call(self);  
  5. ...  
  6.  
  7. util.inherits(ClientRequest, OutgoingMessage); 

6.3 http.Server

http.createServer其實就是創建了一個http.Server對象,關鍵源碼如下:

  1. exports.createServer = function(requestListener) {  
  2. return new Server(requestListener);  
  3. };  
  4. function Server(requestListener) {  
  5. ...  
  6. net.Server.call(this, { allowHalfOpen: true });  
  7. if (requestListener) {  
  8. this.addListener('request', requestListener);  
  9.  
  10. ...  
  11. this.addListener('connection', connectionListener);  
  12. this.timeout = 2 * 60 * 1000; 
  13. ...  
  14.  
  15. util.inherits(Server, net.Server);  
  16. function connectionListener(socket) {  
  17. ...  
  18. socket.on('end', socketOnEnd);  
  19. socket.on('data', socketOnData)  
  20. ...  

有幾個需要要關注的點:

  • 服務的創建依賴于net.server,通過net.server在底層實現服務的創建
  • 默認情況下,服務的超時時間為2分鐘
  • connectionListener處理tcp連接后的行為,跟net保持一致

6.4 http.ServerResponse

看node.org官方是如何介紹server端的response對象的:

This object is created internally by an HTTP server–not by the user. It is passed as the second parameter to the ‘request’ event.

The response implements, but does not inherit from, the Writable Stream interface.

跟http.ClientRequest很像,繼承了OutgoingMessage,沒有繼承Stream.Writable,但是實現了Stream的功能,可以跟Stream.Writable一樣靈活使用:

  1. function ServerResponse(req) {  
  2. ...  
  3. OutgoingMessage.call(this);  
  4. ...  
  5.  
  6. util.inherits(ServerResponse, OutgoingMessage); 

6.5 http.IncomingMessage

An IncomingMessage object is created by http.Server or http.ClientRequest and passed as the first argument to the ‘request’ and ‘response’ event respectively. It may be used to access response status, headers and data.

http.IncomingMessage有兩個地方時被內部創建,一個是作為server端的request,另外一個是作為client請求中的response,同時該類顯示地繼承了Stream.Readable。

  1. function IncomingMessage(socket) {  
  2. Stream.Readable.call(this);  
  3. this.socket = socket;  
  4. this.connection = socket;  
  5. ...  

util.inherits(IncomingMessage, Stream.Readable);

7. 結語

上面是對node中主要的網絡通信模塊,粗略進行了分析研究,對網絡通信的細節有大概的了解。但是這還遠遠不夠的,仍然無法解決node應用中出現的各種網絡問題,這邊文章只是一個開端,希望后面可以深入了解各個細節、深入到c++層面。

責任編輯:未麗燕 來源: 前端之路 - DRY
相關推薦

2020-11-12 08:52:16

Python

2020-11-13 08:30:57

Socket

2009-12-10 15:39:34

動態路由協議

2025-04-07 00:55:00

RustUDP編程

2009-08-24 17:20:13

C#網絡通信TCP連接

2019-04-29 10:26:49

TCP網絡協議網絡通信

2014-09-16 17:00:02

UDP

2010-06-29 10:15:31

局域網故障

2021-08-13 11:27:25

網絡通信數據

2020-07-06 07:52:10

Kubernetes網絡通信

2010-06-09 11:57:42

網絡通信協議

2010-06-14 19:13:28

網絡通信協議

2025-04-17 01:44:00

2010-07-01 15:45:22

網絡通信協議

2022-12-05 09:25:17

Kubernetes網絡模型網絡通信

2024-02-20 19:53:57

網絡通信協議

2025-10-11 02:15:00

GPULLM網絡通信

2016-08-25 11:17:16

CaaS華為

2022-05-13 10:59:14

容器網絡通信

2010-06-09 11:31:55

網絡通信協議
點贊
收藏

51CTO技術棧公眾號

亚洲色欲色欲www| 日韩精品1区2区3区| 91精品亚洲| 国产精品污www在线观看| 91精品国产综合久久香蕉| 欧美人与禽zozzo禽性配| 日韩mv欧美mv国产网站| 欧美精三区欧美精三区 | 欧美视频网址| 日韩欧美国产一区二区在线播放| 欧美牲交a欧美牲交aⅴ免费下载| a视频网址在线观看| 成人黄色在线看| 国产噜噜噜噜久久久久久久久| 久久久久无码精品国产| 欧美一区二区三区高清视频| 欧美成人a∨高清免费观看| 日本www高清视频| 久久99亚洲网美利坚合众国| 国产精品午夜电影| 久久99久久99精品蜜柚传媒| 在线中文字幕网站| 国产视频亚洲| 久久久久久国产精品| 女人黄色一级片| 日韩精选在线| 日韩欧美国产不卡| 久热精品在线播放| 综合久久2023| 亚洲成人动漫av| 50度灰在线观看| 日本最黄一级片免费在线| 9l国产精品久久久久麻豆| 91麻豆桃色免费看| 这里只有精品6| 日韩成人精品在线| 日韩美女视频免费在线观看| 日本熟伦人妇xxxx| 激情欧美日韩一区| 欧美黑人巨大xxx极品| 成人免费毛片xxx| 亚洲av无码乱码国产精品fc2| 99精品视频在线免费播放| 欧美性色19p| 欧美日韩精品在线一区二区 | 国产精品久久一级| 日本一区二区在线视频| 亚洲欧美日韩动漫| 99re热这里只有精品免费视频| 岛国视频一区免费观看| 国产黄色片网站| 国产一区91精品张津瑜| 91香蕉亚洲精品| 国产裸体无遮挡| 国产一区二区三区免费观看| 91亚洲精品久久久| 99久久精品国产成人一区二区 | 成人高清在线| 国产女同性恋一区二区| 亚洲精品视频一区二区三区| 97电影在线观看| 中文字幕中文在线不卡住| 一区二区三区我不卡| 日本高清在线观看wwwww色| 中文字幕巨乱亚洲| 中文字幕综合在线观看| 成人在线播放免费观看| 一区二区三区在线观看国产 | 国产视频不卡在线| 天堂网在线观看国产精品| 日韩视频免费观看| 日韩av手机在线免费观看| 亚洲国产一区二区在线观看| 久久99热精品这里久久精品| 日本一区二区三区免费视频| 亚洲一区不卡| 国产欧美日韩中文字幕| aaa国产视频| av在线不卡免费看| 天堂资源在线亚洲资源| 成人短视频在线| 午夜电影网亚洲视频| 日本成人黄色网| 天堂av一区| 亚洲精品自拍偷拍| 国产精品成人免费视频| 添女人荫蒂视频| 欧美午夜精彩| 欧美日韩国产成人| 麻豆精品久久久久久久99蜜桃| 欧美电影免费网站| 久久综合视频网| 欧美三日本三级少妇三99| 三级外国片在线观看视频| 一区二区理论电影在线观看| 黄在线观看网站| 国产成年精品| 亚洲欧美第一页| 欧美偷拍第一页| 视频一区视频二区中文字幕| 电影午夜精品一区二区三区| 番号集在线观看| 亚洲一区二区黄色| 在线免费观看视频黄| 卡通动漫精品一区二区三区| 日韩在线视频观看| 日韩特级黄色片| 国产一区二区三区视频在线播放| 欧美高清视频一区二区三区在线观看 | 永久免费看mv网站入口| 国产精品日韩欧美一区| 91麻豆蜜桃| 一区二区三区视频网站 | 久久久久999| 天天爽夜夜爽人人爽| 高潮精品一区videoshd| 欧美少妇一级片| 欧美大片免费高清观看| 亚洲成人激情在线观看| 天天色影综合网| 免费在线成人网| 欧美日本韩国在线| 野外性满足hd| 亚洲精品一区二区三区在线| 国产一区二区久久精品| 可以免费看的av毛片| 国产河南妇女毛片精品久久久| 亚洲国产激情一区二区三区| 超碰一区二区| 日韩精品在线免费观看| 99免费在线观看| 成人综合激情网| 男女裸体影院高潮| 成人亚洲精品| 久久精品99久久久久久久久| 中文字幕免费观看视频| 国产欧美日本一区视频| 成年人网站大全| 国产aⅴ精品一区二区三区久久| 91精品国产91久久久久久吃药| 精品人妻aV中文字幕乱码色欲 | 精品粉嫩超白一线天av| 唐朝av高清盛宴| 国模大尺度一区二区三区| 亚洲欧洲国产日韩精品| 国产第一亚洲| 中文字幕日韩av电影| 国产一级精品毛片| 中文字幕第一页久久| 亚洲欧美自偷自拍另类| 日韩激情一区| 91精品久久久久久综合乱菊| 免费黄色电影在线观看| 在线不卡免费欧美| 久久久久久久久久网站| 高清av一区二区| 91专区在线观看| 国产成人ay| 国产精品美女久久久久av超清| 在线国产91| 日韩欧美一区在线| 日本少妇久久久| 26uuu国产日韩综合| 午夜欧美福利视频| 国产韩国精品一区二区三区| 亚洲影院在线看| 2001个疯子在线观看| 亚洲精品在线91| 中文字幕久久网| 亚洲免费观看高清完整版在线观看 | 伊人狠狠色丁香综合尤物| 小h片在线观看| 中文字幕亚洲无线码在线一区| 一级aaaa毛片| 亚洲一区二区精品视频| 亚洲第一香蕉网| 久久福利视频一区二区| 日韩美女爱爱视频| 视频一区在线观看| 成人黄色网免费| 1区2区3区在线| 在线视频中文亚洲| 超碰在线观看99| 欧美色图在线视频| www色aa色aawww| 99精品国产91久久久久久| 一区二区三区韩国| 亚洲视频狠狠| 无遮挡亚洲一区| 亚洲专区**| 国产精品v日韩精品| 国语对白在线刺激| 尤物99国产成人精品视频| 亚洲成人精品女人久久久| 色88888久久久久久影院按摩 | 下面一进一出好爽视频| 久久国产一二区| 国产在线拍揄自揄拍无码| 天堂资源在线亚洲| 亚洲综合在线小说| 日韩一区二区三区在线免费观看 | www成人在线视频| 九九久久久久久久久激情| 国内三级在线观看| 精品久久免费看| 亚洲天堂网在线观看视频| 午夜激情一区二区| 欧美激情精品久久| 国产精品蜜臀av| 一区二区三区四区免费| 国产成人精品三级麻豆| 91 在线视频观看| 日韩电影一区二区三区| 欧美一区二区中文字幕| 国产一区视频在线观看免费| 亚洲视频小说| 精品视频亚洲| 快播亚洲色图| 精品欧美午夜寂寞影院| 亚洲色图一区二区| 久久久久久99| 超碰一区二区三区| 亚洲va欧美va国产综合剧情| jizz免费一区二区三区| 欧美最顶级丰满的aⅴ艳星| 欧美aaaxxxx做受视频| 日韩最新av在线| 国产视频二区在线观看| 亚洲精品一区二区三区不| 欧日韩在线视频| 日韩免费在线观看| 国产高清在线免费| 欧美一区二区免费视频| 国产有码在线观看| 欧美日韩国产乱码电影| 欧美日韩a v| 在线精品亚洲一区二区不卡| 综合网在线观看| 色综合久久天天综合网| 亚洲天堂一区在线观看| 精品久久久久久国产91| 国产精品18p| 午夜国产精品一区| 天天综合网久久综合网| 一本到不卡精品视频在线观看 | 欧美在线免费视屏| 国产一级片av| 欧美三级视频在线| 一区二区三区免费在线视频| 69p69国产精品| 国产日韩精品suv| 日韩欧美国产1| 日本毛片在线观看| 日韩av综合中文字幕| 桃花色综合影院| 亚洲欧美精品suv| 搞黄视频免费在线观看| 日韩一区二区福利| 韩国中文字幕在线| 久久色免费在线视频| av在线播放观看| 久久综合久中文字幕青草| 人妖欧美1区| 97视频在线观看免费| 人人视频精品| 成人xxxx视频| 国产精品网址| 欧美色图亚洲自拍| 91精品成人| 日韩视频免费播放| 日韩专区欧美专区| 国产在线观看中文字幕| 成人黄页毛片网站| 久久久久久久毛片| 亚洲免费黄色| 久久精品国产视频| 2021国产在线| 51精品国产黑色丝袜高跟鞋| 天天综合网站| 亚洲www在线| 欧洲亚洲成人| 国产对白在线播放| 国产一区二区三区成人欧美日韩在线观看 | 欧美涩涩视频| 国产成人综合一区| 国产精品羞羞答答xxdd| 国产精品三级在线观看无码| 国产精品视频看| 福利一区二区三区四区| 欧美亚洲国产一卡| 性欧美18一19性猛交| 一个人www欧美| 久草在线视频网站| 国产精品视频大全| 日本福利一区| 9l视频自拍9l视频自拍| 噜噜噜躁狠狠躁狠狠精品视频| 五月天开心婷婷| 91亚洲精品久久久蜜桃网站| 乱老熟女一区二区三区| 都市激情亚洲色图| 精品区在线观看| 日韩在线观看免费网站| 欧美aa免费在线| 3d精品h动漫啪啪一区二区| 成人av资源电影网站| 一二三四视频社区在线| 久久99久久久欧美国产| 亚洲av无码国产精品久久| 一区二区三区四区不卡视频| 自拍偷拍精品视频| 葵司免费一区二区三区四区五区| 91在线观看免费网站| 欧美丝袜足交| 国产玉足脚交久久欧美| 黄一区二区三区| 免费看91的网站| 色婷婷久久综合| 手机福利小视频在线播放| 欧美激情一区二区三区久久久| 日日夜夜亚洲精品| 日韩午夜视频在线观看| 久久国产精品99国产| 亚洲精品乱码久久久久久蜜桃图片| 亚洲天天做日日做天天谢日日欢| 中文字幕 国产| 亚洲欧美日韩第一区| 色综合亚洲图丝熟| 国产在线欧美日韩| 伊人久久大香线蕉av超碰演员| 6080国产精品| 国产精品夫妻自拍| 中文字字幕在线中文乱码| 亚洲人永久免费| 电影网一区二区| 欧美h视频在线| 天堂成人免费av电影一区| 久久久久国产精品区片区无码| 精品国产精品自拍| 神马久久高清| 日本中文字幕不卡免费| 怕怕欧美视频免费大全| 欧美私人情侣网站| 国产日产欧美一区| 日本成人一级片| 深夜福利91大全| av在线国产精品| www.69av| 成人午夜在线视频| 天天操天天爽天天干| 亚洲精品一区在线观看香蕉| 英国三级经典在线观看| 欧美亚洲丝袜| 青青草伊人久久| 多男操一女视频| 日韩亚洲欧美综合| 狂野欧美性猛交xxxxx视频| 国产精品久久久久久久久久直播 | 99福利在线观看| 国产午夜精品在线观看| 一区二区视频网| 欧美乱人伦中文字幕在线| 成人激情自拍| 久草在在线视频| 亚洲欧美一区二区在线观看| av中文字幕第一页| 2020国产精品视频| 欧美日韩有码| 亚洲一区精品视频在线观看| 亚洲理论在线观看| 日韩三级电影网| 国产日韩精品综合网站| 欧美日韩亚洲一区在线观看| 99久久免费看精品国产一区| 欧美在线制服丝袜| 深夜国产在线播放| 欧美日韩国产综合视频在线| 美女高潮久久久| 久久精品久久精品久久| 亚洲视频一区二区| 欧美午夜在线播放| 黄色网页免费在线观看| 国产精品伦一区二区三级视频| 99riav国产| 国产精品69久久久久| 欧美1区2区| 欧美人妻一区二区三区| 日韩欧美一卡二卡| 91p九色成人| 欧美男女爱爱视频| 国产精品久久久久三级| 少妇高潮一区二区三区69| 国产精品狼人色视频一区| 亚洲视频一区| 在线视频这里只有精品| 日韩av在线资源| 天堂精品久久久久| 在线免费视频一区| 岛国av一区二区在线在线观看| 三区四区在线视频|