成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

初步研究node中的網(wǎng)絡(luò)通信模塊

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

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

1. Socket

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

  • 可以實(shí)現(xiàn)底層通信,幾乎所有的應(yīng)用層都是通過(guò)socket進(jìn)行通信的,因此『一切且socket』
  • 對(duì)TCP/IP協(xié)議進(jìn)行封裝,便于應(yīng)用層協(xié)議調(diào)用,屬于二者之間的中間抽象層
  • 各個(gè)語(yǔ)言都與相關(guān)實(shí)現(xiàn),例如C、C++、node
  • TCP/IP協(xié)議族中,傳輸層存在兩種通用協(xié)議: TCP、UDP,兩種協(xié)議不同,因?yàn)椴煌瑓?shù)的socket實(shí)現(xiàn)過(guò)程也不一樣

初步研究node中的網(wǎng)絡(luò)通信模塊

2. node中網(wǎng)絡(luò)通信的架構(gòu)實(shí)現(xiàn)

node中的模塊,從兩種語(yǔ)言實(shí)現(xiàn)角度來(lái)說(shuō),存在javscript、c++兩部分,通過(guò) process.binding 來(lái)建立關(guān)系。具體分析如下:

  • 標(biāo)準(zhǔn)的node模塊有net、udp、dns、http、tls、https等
  • V8是chrome的內(nèi)核,提供了javascript解釋運(yùn)行功能,里面包含tcp_wrap.h、udp_wrap.h、tls_wrap.h等
  • OpenSSL是基本的密碼庫(kù),包括了MD5、SHA1、RSA等加密算法,構(gòu)成了node標(biāo)準(zhǔn)模塊中的 crypto
  • cares模塊用于DNS的解析
  • libuv實(shí)現(xiàn)了跨平臺(tái)的異步編程
  • http_parser用于http的解析

初步研究node中的網(wǎng)絡(luò)通信模塊

3. net使用

net模塊 是基于TCP協(xié)議的socket網(wǎng)路編程模塊,http模塊就是建立在該模塊的基礎(chǔ)上實(shí)現(xiàn)的,先來(lái)看看基本使用方法:

  1. // 創(chuàng)建socket服務(wù)器 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. // 創(chuàng)建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. // 打開兩個(gè)終端,分別執(zhí)行`node server.js`、`node client.js`,可以看到客戶端與服務(wù)器進(jìn)行了數(shù)據(jù)通信。 

使用 const server = net.createServer(); 創(chuàng)建了server對(duì)象,那server對(duì)象有哪些特點(diǎn):

  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); 

上述代碼可以分為幾個(gè)點(diǎn):

  • createServer 就是一個(gè)語(yǔ)法糖,幫助new生成server對(duì)象
  • server對(duì)象繼承了EventEmitter,具有事件的相關(guān)方法
  • _handle是server處理的句柄,屬性值最終由c++部分的 TCP 、 Pipe 類創(chuàng)建
  • connectionListener也是語(yǔ)法糖,作為connection事件的回調(diào)函數(shù)

再來(lái)看看connectionListener事件的回調(diào)函數(shù),里面包含一個(gè) socket 對(duì)象,該對(duì)象是一個(gè)連接套接字,是個(gè)五元組(server_host、server_ip、protocol、client_host、client_ip),相關(guān)實(shí)現(xiàn)如下:

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

因?yàn)镾ocket是繼承了 stream.Duplex ,所以Socket也是一個(gè)可讀可寫流,可以使用流的方法進(jìn)行數(shù)據(jù)的處理。

接下來(lái)就是很關(guān)鍵的端口監(jiān)聽(port),這是server與client的主要區(qū)別,代碼:

  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);  

上述代碼有幾個(gè)點(diǎn)需要注意:

  • 監(jiān)聽的對(duì)象可以是端口、路徑、定義好的server句柄、文件描述符
  • 當(dāng)通過(guò)cluster創(chuàng)建工作進(jìn)程(worker)時(shí),exclusive判斷是否進(jìn)行socket連接的共享
  • 事件監(jiān)聽最終還是通過(guò)TCP/Pipe的listen來(lái)實(shí)現(xiàn)
  • backlog規(guī)定了socket連接的限制,默認(rèn)最多為511

接下來(lái)分析下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實(shí)現(xiàn),因而要想完全搞清楚node中的網(wǎng)絡(luò)通信,必須深入到V8的源碼里面。

4. UDP/dgram使用

跟net模塊相比,基于UDP通信的dgram模塊就簡(jiǎn)單了很多,因?yàn)椴恍枰ㄟ^(guò)三次握手建立連接,所以整個(gè)通信的過(guò)程就簡(jiǎn)單了很多,對(duì)于數(shù)據(jù)準(zhǔn)確性要求不太高的業(yè)務(wù)場(chǎng)景,可以使用該模塊完成數(shù)據(jù)的通信。

  1. // server端實(shí)現(xiàn)  
  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端實(shí)現(xiàn)  
  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. }); 

從源碼層面分析上述代碼的原理實(shí)現(xiàn):

  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. ...  

上述代碼存在幾個(gè)點(diǎn)需要注意:

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

5. DNS使用

DNS(Domain Name System)用于域名解析,也就是找到host對(duì)應(yīng)的ip地址,在計(jì)算機(jī)網(wǎng)絡(luò)中,這個(gè)工作是由網(wǎng)絡(luò)層的ARP協(xié)議實(shí)現(xiàn)。在node中存在 net 模塊來(lái)完成相應(yīng)功能,其中dns里面的函數(shù)分為兩類:

依賴底層操作系統(tǒng)實(shí)現(xiàn)域名解析,也就是我們?nèi)粘i_發(fā)中,域名的解析規(guī)則,可以回使用瀏覽器緩存、本地緩存、路由器緩存、dns服務(wù)器,該類僅有 dns.lookup

該類的dns解析,直接到nds服務(wù)器執(zhí)行域名解析

  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 

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

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

接下來(lái)分析下dns的內(nèi)部實(shí)現(xiàn):

  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. ... 

上面的源碼有幾個(gè)點(diǎn)需要關(guān)注:

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

6. HTTP使用

在WEB開發(fā)中,HTTP作為***、最重要的應(yīng)用層,是每個(gè)開發(fā)人員應(yīng)該熟知的基礎(chǔ)知識(shí),我面試的時(shí)候必問(wèn)的一塊內(nèi)容。同時(shí),大多數(shù)同學(xué)接觸node時(shí),首先使用的恐怕就是http模塊。先來(lái)一個(gè)簡(jiǎn)單的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. // 輸出結(jié)果如下:  
  21. // server is on { address: '::', family: 'IPv6', port: 3000 }  
  22. // data from server

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

6.1 http.Agent

因?yàn)镠TTP協(xié)議是無(wú)狀態(tài)協(xié)議,每個(gè)請(qǐng)求均需通過(guò)三次握手建立連接進(jìn)行通信,眾所周知三次握手、慢啟動(dòng)算法、四次揮手等過(guò)程很消耗時(shí)間,因此HTTP1.1協(xié)議引入了keep-alive來(lái)避免頻繁的連接。那么對(duì)于tcp連接該如何管理呢?http.Agent就是做這個(gè)工作的。先看看源碼中的關(guān)鍵部分:

  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 = {}; // 請(qǐng)求隊(duì)列  
  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. // 關(guān)于socket的相關(guān)增刪改查操作  
  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(); 

上述代碼有幾個(gè)點(diǎn)需要注意:

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

下面可以測(cè)試下agent對(duì)請(qǐng)求本身的限制:

  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. // 在終端中執(zhí)行time node ./req.js,結(jié)果為:  
  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,結(jié)果為:  
  28. real 0m4.141s  
  29. user 0m0.103s  
  30. sys 0m0.024s 

當(dāng)設(shè)置maxSockets為某個(gè)值時(shí),tcp的連接就會(huì)被限制在某個(gè)值,剩余的請(qǐng)求就會(huì)進(jìn)入 requests 隊(duì)列里面,等有空余的socket連接后,從request隊(duì)列中出棧,發(fā)送請(qǐng)求。

6.2 http.ClientRequest

當(dāng)執(zhí)行http.request時(shí),會(huì)生成ClientRequest對(duì)象,該對(duì)象雖然沒有直接繼承Stream.Writable,但是繼承了http.OutgoingMessage,而http.OutgoingMessage實(shí)現(xiàn)了write、end方法,因?yàn)榭梢援?dāng)跟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請(qǐng)求中添加數(shù)據(jù)  
  7. fs.createReadStream('./data.json').pipe(req); 

接下來(lái),看看http.ClientRequest的實(shí)現(xiàn), 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其實(shí)就是創(chuàng)建了一個(gè)http.Server對(duì)象,關(guān)鍵源碼如下:

  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. ...  

有幾個(gè)需要要關(guān)注的點(diǎn):

  • 服務(wù)的創(chuàng)建依賴于net.server,通過(guò)net.server在底層實(shí)現(xiàn)服務(wù)的創(chuàng)建
  • 默認(rèn)情況下,服務(wù)的超時(shí)時(shí)間為2分鐘
  • connectionListener處理tcp連接后的行為,跟net保持一致

6.4 http.ServerResponse

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

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,但是實(shí)現(xiàn)了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有兩個(gè)地方時(shí)被內(nèi)部創(chuàng)建,一個(gè)是作為server端的request,另外一個(gè)是作為client請(qǐng)求中的response,同時(shí)該類顯示地繼承了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. 結(jié)語(yǔ)

上面是對(duì)node中主要的網(wǎng)絡(luò)通信模塊,粗略進(jìn)行了分析研究,對(duì)網(wǎng)絡(luò)通信的細(xì)節(jié)有大概的了解。但是這還遠(yuǎn)遠(yuǎn)不夠的,仍然無(wú)法解決node應(yīng)用中出現(xiàn)的各種網(wǎng)絡(luò)問(wèn)題,這邊文章只是一個(gè)開端,希望后面可以深入了解各個(gè)細(xì)節(jié)、深入到c++層面。

責(zé)任編輯:未麗燕 來(lái)源: 前端之路 - DRY
相關(guān)推薦

2020-11-12 08:52:16

Python

2020-11-13 08:30:57

Socket

2009-12-10 15:39:34

動(dòng)態(tài)路由協(xié)議

2025-04-07 00:55:00

RustUDP編程

2009-08-24 17:20:13

C#網(wǎng)絡(luò)通信TCP連接

2019-04-29 10:26:49

TCP網(wǎng)絡(luò)協(xié)議網(wǎng)絡(luò)通信

2014-09-16 17:00:02

UDP

2010-06-14 19:13:28

網(wǎng)絡(luò)通信協(xié)議

2021-08-13 11:27:25

網(wǎng)絡(luò)通信數(shù)據(jù)

2020-07-06 07:52:10

Kubernetes網(wǎng)絡(luò)通信

2010-06-09 11:57:42

網(wǎng)絡(luò)通信協(xié)議

2010-06-29 10:15:31

局域網(wǎng)故障

2010-07-01 15:45:22

網(wǎng)絡(luò)通信協(xié)議

2025-04-17 01:44:00

2022-12-05 09:25:17

Kubernetes網(wǎng)絡(luò)模型網(wǎng)絡(luò)通信

2024-02-20 19:53:57

網(wǎng)絡(luò)通信協(xié)議

2010-06-09 11:31:55

網(wǎng)絡(luò)通信協(xié)議

2016-08-25 11:17:16

CaaS華為

2022-05-13 10:59:14

容器網(wǎng)絡(luò)通信

2009-10-16 08:48:08

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 一区二区在线不卡 | 四虎影音| 欧美中文在线 | 色秀网站| 伊人春色在线观看 | 这里只有精品99re | 欧美日韩中文国产一区发布 | 在线成人免费视频 | 亚洲国产中文在线 | 青青久在线视频 | 99一级毛片| 天天干天天谢 | 日日夜夜影院 | 97超碰在线播放 | 亚洲高清在线 | 欧美一区二区在线看 | 国产高清精品一区二区三区 | 日韩综合网 | 欧美黄色一区 | 在线观看中文字幕 | 中文字幕av一区 | 免费啪啪 | 国产精品久久久久久久久免费桃花 | 日韩视频在线观看中文字幕 | 日本成人片在线观看 | 一区二区三区在线免费观看 | 91精品国产综合久久久动漫日韩 | 操视频网站 | 中文字幕亚洲欧美日韩在线不卡 | 免费一级黄色录像 | 中文字幕在线第一页 | 日韩欧美一级片 | 精品欧美一区二区在线观看欧美熟 | 国产精品高潮呻吟久久av野狼 | 国产精品成人一区二区三区 | 日韩国产欧美一区 | av男人的天堂在线 | 99热这里 | 日韩中文字幕一区二区三区 | 日韩和的一区二在线 | 久久影音先锋 |