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

曰本一区二区三区视频| 性欧美1819sex性高清大胸| 日韩黄色小视频| 久久综合伊人77777| 欧洲熟妇的性久久久久久| 女海盗2成人h版中文字幕| 国产精品三级久久久久三级| 2022国产精品| 无码人妻丰满熟妇奶水区码| 亚洲色图插插| 亚洲欧美一区二区三区四区| 亚洲黄色片免费| 69久成人做爰电影| 亚洲三级小视频| 欧美日韩高清免费| www.黄色国产| 免费久久精品视频| 97在线视频免费观看| 中文乱码字幕高清一区二区| 秋霞影视一区二区三区| 欧美片在线播放| 国产aaa一级片| 在线播放免费av| 国产精品女人毛片| 欧美男人的天堂| 色婷婷av一区二区三| 国产一区二区女| 国产三级精品网站| 久久人人爽人人爽人人片av免费| 欧美精品观看| 久久亚洲一区二区三区四区五区高| 99久久人妻精品免费二区| 欧美久久亚洲| 91精品国产综合久久久蜜臀粉嫩| 午夜视频在线瓜伦| 色综合桃花网| 欧美性极品少妇精品网站| 国产九色porny| 少女频道在线观看高清| 中文字幕中文乱码欧美一区二区| 欧美一区免费视频| 污视频在线免费观看| 国产91精品免费| 成人免费91在线看| 精品久久久久久亚洲综合网站| 久久er99精品| 成人免费午夜电影| 国产又粗又猛又爽| 精品一区二区三区蜜桃| 成人福利免费观看| 国产又大又黄的视频| 精品一区精品二区高清| 国产精品视频区| 最近中文字幕在线观看| 秋霞电影网一区二区| 国产精品91视频| 成人h动漫精品一区二区下载 | 亚洲美女av在线| 午夜av免费看| 少妇精品久久久一区二区| 亚洲欧美在线第一页| 深爱五月激情网| 国产伦精品一区二区三区视频| 国产一区二区精品丝袜| 国产黄色片在线| 天天揉久久久久亚洲精品| 久久天天躁狠狠躁老女人| 国产一区二区视频在线观看免费| **女人18毛片一区二区| 九九热精品视频国产| 国产一级性生活| 亚洲综合精品| 国产精品自产拍在线观看| 136福利视频导航| 国产精品夜夜嗨| 激情伦成人综合小说| 国产高清在线| 亚洲欧美在线aaa| www.国产在线播放| 不卡福利视频| 欧美日韩国产一级二级| 在线观看你懂的视频| 牛牛影视一区二区三区免费看| 国产亚洲精品久久久久久| 国产又黄又粗又猛又爽的| 888久久久| 91爱视频在线| 亚洲综合一区中| 成人sese在线| 日韩欧美视频一区二区| 成人日批视频| 欧美日韩在线免费观看| 中文字幕第100页| 国产精品自在线拍| 中日韩美女免费视频网站在线观看| 欧美风情第一页| 一本色道久久| 91精品综合视频| 婷婷丁香花五月天| 中文字幕日韩av资源站| 欧美精品一区免费| 国产精品视频一区视频二区 | 欧美天堂一区二区三区| 2025中文字幕| 日韩精品2区| 国模精品视频一区二区三区| 瑟瑟视频在线免费观看| 成人av资源网站| 婷婷视频在线播放| 国产精品av一区二区三区| 欧美一区二区私人影院日本| 久久精品—区二区三区舞蹈 | 欧美黄色三级网站| 中文字幕在线观看视频一区| 91亚洲精品久久久蜜桃| 日本一二三区视频在线| 在线一区视频观看| 岛国片av在线| 久久―日本道色综合久久| 制服国产精品| 你懂得影院夜精品a| 精品国产1区二区| 婷婷社区五月天| 日韩高清在线一区| 国产v亚洲v天堂无码| 美女国产在线| 欧美性猛交xxxx乱大交退制版| 日本一卡二卡在线| 狠狠88综合久久久久综合网| 亚洲精品免费网站| 欧美69xxxx| 欧美日韩免费高清一区色橹橹 | 成人精品影视| 日本精品久久久| 人成网站在线观看| 亚洲午夜在线视频| 一级黄色大片免费看| 亚洲久久久久| 成人做爽爽免费视频| 在线观看a视频| 在线观看一区日韩| 西西444www无码大胆| 欧美亚洲三区| 欧美精品免费观看二区| 91av亚洲| 亚洲精品中文字幕有码专区| 999这里只有精品| 91香蕉视频污| 国产主播在线看| 竹菊久久久久久久| 日本亚洲欧洲色| 黄色视屏网站在线免费观看| 在线国产亚洲欧美| wwwww黄色| 国模少妇一区二区三区| 日本黄色a视频| 欧美久久亚洲| 久久久亚洲精选| 亚洲欧美日韩综合在线| 色综合天天综合给合国产| 欧美 日韩 国产 成人 在线观看 | 天天做综合网| 91亚洲精品一区二区| 最新av在线播放| 激情五月婷婷综合| 欧美美女激情18p| 在线免费观看视频| 老色鬼精品视频在线观看播放| 亚洲在线视频一区二区| 99综合久久| 久久免费福利视频| 青春有你2免费观看完整版在线播放高清| 欧美视频不卡中文| 99自拍偷拍视频| 国产99久久久国产精品潘金| 俄罗斯av网站| 日韩在线观看一区| 成人xxxxx色| 成人欧美一区二区三区的电影| 国产亚洲精品高潮| a在线观看视频| 欧美午夜激情在线| 免费成人深夜蜜桃视频| 成人网页在线观看| 久久综合久久色| 欧美成人国产| 日本不卡免费新一二三区| 高清一区二区| 欧美一级视频在线观看| 欧美黄色激情| 国产视频精品va久久久久久| 又骚又黄的视频| 五月婷婷综合在线| 国产真人真事毛片视频| 大陆成人av片| 手机看片一级片| 亚洲少妇在线| 一区二区三区四区免费观看| 国产精品亚洲人成在99www| 成人精品久久一区二区三区| 99久久伊人精品影院| 免费不卡视频| 精品亚洲男同gayvideo网站| 国产乱码精品一区二区| 欧美视频在线免费看| 永久免费看黄网站| 欧美激情在线一区二区三区| 18禁一区二区三区| 卡一卡二国产精品| 成人av一级片| 影音先锋一区| 亚洲成人动漫在线| 国产一区二区三区网| 国产chinese精品一区二区| 欧美激情不卡| 国产精品久久久久久久久借妻| aaa在线播放视频| 欧美xxxx18性欧美| 91av资源在线| 亚洲男人天堂久| 天堂网在线资源| 欧美一区二区精品久久911| 国产精品成人久久久| 日韩欧美中文在线| 日本一级淫片免费放| 一区二区三区四区视频精品免费| 精品手机在线视频| 国产亚洲短视频| 久久亚洲AV成人无码国产野外 | 欧美二区三区的天堂| 亚洲 欧美 成人| 午夜精品久久一牛影视| 久艹视频在线观看| 亚洲人一二三区| 精品国产视频一区二区三区| 亚洲欧洲精品一区二区精品久久久| 91资源在线播放| 天天摸夜夜添狠狠添婷婷| 色先锋资源久久综合| wwwxxx亚洲| 午夜激情久久久| 国产精品第九页| 亚洲高清在线精品| 69精品久久久| 偷拍与自拍一区| 六月丁香在线视频| 日韩欧美国产免费播放| 国产又粗又爽视频| 91精品1区2区| 瑟瑟视频在线免费观看| 欧美色视频一区| 一级黄色录像大片| 欧美精品欧美精品系列| 6—12呦国产精品| 日韩欧美一卡二卡| 精品国产亚洲av麻豆| 亚洲成avwww人| 午夜在线视频免费| 亚洲色图五月天| 92国产在线视频| 久久精品国产91精品亚洲| 含羞草www国产在线视频| 欧美成在线视频| 成人国产电影在线观看| 国产99视频精品免视看7| 粉嫩91精品久久久久久久99蜜桃| 国产在线日韩在线| 国产亚洲久久| 国产一区二区三区四区五区在线 | 影音先锋欧美精品| 欧美激情二区| 欧美激情亚洲一区| 中文字幕人成乱码在线观看| 国产精品美女www| 亚洲精品一二三**| 久久婷婷人人澡人人喊人人爽| 欧美熟乱15p| 日韩欧美视频免费在线观看| 性欧美长视频| 午夜免费一级片| 91在线视频官网| 五月天婷婷丁香网| 亚洲国产精品一区二区www | 九九在线观看视频| 欧美视频在线观看免费网址| 一区二区视频在线观看| 澳门成人av网| 成人在线视频网| 欧美日韩另类图片| 五月天亚洲综合情| 国产精品第十页| 在线视频日韩一区| 国产成人午夜视频| 国产aⅴ激情无码久久久无码| 亚洲人成人一区二区在线观看| 特一级黄色大片| 8v天堂国产在线一区二区| 手机看片1024国产| www国产精品视频| 欧美三级网站| av噜噜色噜噜久久| 日韩夫妻性生活xx| 俄罗斯av网站| 国产成人8x视频一区二区| 精品无码在线观看| 精品久久久一区二区| 国产男男gay体育生白袜| 亚洲人成伊人成综合网久久久 | 亚洲一区二区美女| 久久久久精彩视频| 亚洲精品福利在线观看| 大片免费在线看视频| 国产精品草莓在线免费观看| 黑色丝袜福利片av久久| 一区二区三区四区免费观看| 日本免费新一区视频| 少妇特黄一区二区三区| 亚洲韩国精品一区| 国产区精品在线| 中文字幕久精品免费视频| 欧美gv在线观看| 国产欧美一区二区视频| 亚洲色图二区| 污污的网站免费| 中文字幕av一区 二区| 国产婷婷色一区二区在线观看| 亚洲国产成人精品女人久久久 | 91精品免费在线观看| 国产三级在线免费观看| 欧美一级高清免费| 99久久人爽人人添人人澡 | 亚洲久色影视| 91成人在线观看喷潮蘑菇| 亚洲男人电影天堂| 91成人一区二区三区| 色噜噜亚洲精品中文字幕| 日韩视频网站在线观看| 日本精品二区| 老司机免费视频久久| 亚洲欧美视频在线播放| 黄色一区二区三区| 黄色aaa毛片| 高清欧美性猛交xxxx黑人猛交| 日本伊人久久| 欧美日韩午夜爽爽| 国产美女精品一区二区三区| tube国产麻豆| 日韩欧美国产综合| 欧美人与禽性xxxxx杂性| 成人女人免费毛片| 一区久久精品| 国产 中文 字幕 日韩 在线| 天天影视网天天综合色在线播放 | 日韩一区二区av| 国产精品va视频| 黄网站色视频免费观看| 成人免费毛片aaaaa**| 欧美激情喷水视频| 欧美gay视频| 亚洲精品中文字幕在线| 精品一区二区在线播放| 真实国产乱子伦对白在线| 精品国产乱码久久久久久图片| 9765激情中文在线| 欧美国产综合视频| 免费在线观看不卡| 91嫩草丨国产丨精品| 精品久久久久久最新网址| 国产精选在线| 日韩精品久久一区二区三区| 久久99国产精品久久99果冻传媒| 久艹视频在线观看| 亚洲毛茸茸少妇高潮呻吟| 免费一级欧美在线观看视频| 日本久久久网站| 久久青草国产手机看片福利盒子| 在线观看国产区| 欧美日韩成人黄色| 秋霞在线一区| www.色欧美| 激情懂色av一区av二区av| 国模精品一区二区| 91精品视频网站| 亚洲一区二区毛片| 日韩一区二区三区四区视频| 欧美精品一区二区在线观看| 欧美电影免费观看网站| 精品91一区二区三区| 成人18精品视频| 在线免费av网| 韩国一区二区电影| 999久久久免费精品国产| 中国极品少妇videossexhd| 欧美日本在线一区| 老司机深夜福利在线观看| 在线电影看在线一区二区三区| 99视频超级精品| 国产日韩一级片| 国产成人精品一区二区三区| 亚洲先锋成人|