Node.js 網(wǎng)絡(luò)

2022-02-26 10:31 更新
穩(wěn)定性: 3 - 穩(wěn)定

net模塊提供了異步網(wǎng)絡(luò)封裝,該Node.js模塊包含了創(chuàng)建服務(wù)器/客戶端的方法(調(diào)用 streams),你可以通過(guò)調(diào)用 require('net') 包含這個(gè)模塊,訪問方法如下所示:

const net = require('net');

net.createServer([options][, connectionListener])

創(chuàng)建一個(gè)TCP服務(wù)器。參數(shù)connectionListener自動(dòng)給'connection'事件創(chuàng)建監(jiān)聽器。

options包含有以下默認(rèn)值:

{
  allowHalfOpen: false,
  pauseOnConnect: false
}

如果allowHalfOpen=true,當(dāng)另一端socket發(fā)送FIN包時(shí),socket不會(huì)自動(dòng)發(fā)送FIN包。socket變?yōu)椴豢勺x,但仍可寫。你需要顯式的調(diào)用end()方法。更多信息參見'end'事件。

如果pauseOnConnect=true,當(dāng)連接到來(lái)的時(shí)候相關(guān)聯(lián)的socket將會(huì)暫停。它允許在初始進(jìn)程不讀取數(shù)據(jù)情況下,讓連接在進(jìn)程間傳遞。調(diào)用resume()從暫停的socket里讀取數(shù)據(jù)。

下面是一個(gè)監(jiān)聽8124端口連接的應(yīng)答服務(wù)器的例子:

var net = require('net');
var server = net.createServer(function(c) { //'connection' listener
  console.log('client connected');
  c.on('end', function() {
    console.log('client disconnected');
  });
  c.write('hello\r\n');
  c.pipe(c);
});
server.listen(8124, function() { //'listening' listener
  console.log('server bound');
});

使用telnet來(lái)測(cè)試:

telnet localhost 8124

要監(jiān)聽socket t/tmp/echo.sock,僅需要改倒數(shù)第三行代碼,如下所示:

server.listen('/tmp/echo.sock', function() { //'listening' listener

使用nc連接到一個(gè)UNIX domain socket服務(wù)器:

nc -U /tmp/echo.sock

net.connect(options[, connectionListener])

net.createConnection(options[, connectionListener])

工廠方法,返回一個(gè)新的'net.Socket',并連接到指定的地址和端口。

當(dāng)socket建立的時(shí)候,將會(huì)觸發(fā)'connect'事件。

'net.Socket'有相同的方法。

對(duì)于TCP sockets,參數(shù)options因?yàn)橄铝袇?shù)的對(duì)象:

  • port: 客戶端連接到Port的端口(必須)。

  • host: 客戶端要連接到得主機(jī)。默認(rèn)'localhost'.

  • localAddress: 網(wǎng)絡(luò)連接綁定的本地接口。

  • localPort: 網(wǎng)絡(luò)連接綁定的本地端口。

  • family : IP棧版本。默認(rèn)4

對(duì)于本地域socket,參數(shù)options因?yàn)橄铝袇?shù)的對(duì)象:

  • path: 客戶端連接到得路徑(必須).

通用選項(xiàng):

  • 如果allowHalfOpen=true, 當(dāng)另一端socket發(fā)送FIN包時(shí)socket不會(huì)自動(dòng)發(fā)送FIN包。socket變?yōu)椴豢勺x,但仍可寫。你需要顯式的調(diào)用end()方法。更多信息參見'end'事件。

    connectListener參數(shù)將會(huì)作為監(jiān)聽器添加到'connect'事件上。

下面是一個(gè)用上述方法應(yīng)答服務(wù)器的客戶端例子:

var net = require('net');
var client = net.connect({port: 8124},
    function() { //'connect' listener
  console.log('connected to server!');
  client.write('world!\r\n');
});
client.on('data', function(data) {
  console.log(data.toString());
  client.end();
});
client.on('end', function() {
  console.log('disconnected from server');
});

要連接到socket/tmp/echo.sock,僅需將第二行代碼改為如下的內(nèi)容:

var client = net.connect({path: '/tmp/echo.sock'});

net.connect(port[, host][, connectListener])

net.createConnection(port[, host][, connectListener])

創(chuàng)建一個(gè)到端口port和主機(jī)host的TCP連接。如果忽略主機(jī)host,則假定為'localhost'。參數(shù)connectListener將會(huì)作為監(jiān)聽器添加到'connect'事件。

這是工廠方法,返回一個(gè)新的'net.Socket'

net.connect(path[, connectListener])

net.createConnection(path[, connectListener])

創(chuàng)建到path的unix socket連接。參數(shù)connectListener將會(huì)作為監(jiān)聽器添加到'connect'事件上。

這是工廠方法,返回一個(gè)新的'net.Socket'。

Class: net.Server

這個(gè)類用來(lái)創(chuàng)建一個(gè)TCP或本地服務(wù)器。

server.listen(port[, host][, backlog][, callback])

開始接受指定端口port和主機(jī)host的連接。如果忽略主機(jī)host, 服務(wù)器將會(huì)接受任何IPv4地址(INADDR_ANY)的直接連接。端口為0,則會(huì)分配一個(gè)隨機(jī)端口。

積壓量(Backlog)為連接等待隊(duì)列的最大長(zhǎng)度。實(shí)際長(zhǎng)度由您的操作系統(tǒng)通過(guò) sysctl 設(shè)定,比如 linux 上的tcp_max_syn_backlogsomaxconn。這個(gè)參數(shù)默認(rèn)值是511(不是512)。

這是異步函數(shù)。當(dāng)服務(wù)器被綁定時(shí)會(huì)觸發(fā)'listening'事件。最后一個(gè)參數(shù)callback將會(huì)作為'listening'事件的監(jiān)聽器。

有些用戶會(huì)遇到EADDRINUSE錯(cuò)誤,它表示另外一個(gè)服務(wù)器已經(jīng)運(yùn)行在所請(qǐng)求的端口上。處理這個(gè)情況的辦法是等一段事件再重試:

server.on('error', function (e) {
  if (e.code == 'EADDRINUSE') {
    console.log('Address in use, retrying...');
    setTimeout(function () {
      server.close();
      server.listen(PORT, HOST);
    }, 1000);
  }
});

(注意:Node中的所有socket已設(shè)置了SO_REUSEADDR)

server.listen(path[, callback])

  • path {String}
  • callback {Function}

啟動(dòng)一個(gè)本地socket服務(wù)器,監(jiān)聽指定path的連接。

這是異步函數(shù)。綁定服務(wù)器后,會(huì)觸發(fā)'listening'事件。最后一個(gè)參數(shù)callback將會(huì)作為'listening'事件的監(jiān)聽器。

UNIX上,本地域通常默認(rèn)為UNIX域。參數(shù)path是文件系統(tǒng)路徑,就和創(chuàng)建文件時(shí)一樣,它也遵從命名規(guī)則和權(quán)限檢查,并且在文件系統(tǒng)里可見,并持續(xù)到關(guān)閉關(guān)聯(lián)。

Windows上,本地域通過(guò)命名管道實(shí)現(xiàn)。路徑必須是以\\?\pipe\\\.\pipe\入口。任意字符串都可以,不過(guò)之后進(jìn)行相同的管道命名處理,比如解決..序列。管道命名空間是平的。管道不會(huì)一直持久,當(dāng)最后一個(gè)引用關(guān)閉的時(shí)候,管道將會(huì)移除。不要忘記javascript字符字符串轉(zhuǎn)義要求路徑使用雙反斜杠,比如:

net.createServer().listen(
    path.join('\\\\?\\pipe', process.cwd(), 'myctl'))

server.listen(handle[, callback])

  • handle {Object}
  • callback {Function}

    handle 對(duì)象可以設(shè)置成server或socket(任意以下劃線_handle開頭的類),或者是{fd: <n>}對(duì)象。

這將是服務(wù)器用指定的句柄接收連接,前提是文件描述符或句柄已經(jīng)綁定到端口或域socket。

Windows不支持監(jiān)聽文件句柄。

這是異步函數(shù)。當(dāng)服務(wù)器已經(jīng)被綁定,將會(huì)觸發(fā)'listening'事件。最后一個(gè)參數(shù)callback將會(huì)作為'listening'事件的監(jiān)聽器。

server.listen(options[, callback])

  • options {Object} - 必須有。支持以下屬性:
    • port {Number} - 可選。
    • host {String} - 可選。
    • backlog {Number} - 可選。
    • path {String} - 可選。
    • exclusive {Boolean} - 可選。
  • callback {Function} - 可選。

options的屬性:端口port,主機(jī)host,和backlog,以及可選參數(shù)callback函數(shù),他們?cè)谝黄鹫{(diào)用server.listen(port, [host], [backlog], [callback])。還有,參數(shù)path可以用來(lái)指定UNIX socket。

如果參數(shù)exclusivefalse(默認(rèn)值),集群進(jìn)程將會(huì)使用同一個(gè)句柄,允許連接共享。當(dāng)參數(shù)exclusivetrue時(shí),句柄不會(huì)共享,如果共享端口會(huì)返回錯(cuò)誤。監(jiān)聽獨(dú)家端口例子如下:

server.listen({
  host: 'localhost',
  port: 80,
  exclusive: true
});

server.close([callback])

服務(wù)器停止接收新的連接,保持現(xiàn)有連接。這是異步函數(shù),當(dāng)所有連接結(jié)束的時(shí)候服務(wù)器會(huì)關(guān)閉,并會(huì)觸發(fā)'close'事件。你可以傳一個(gè)回調(diào)函數(shù)來(lái)監(jiān)聽'close' 事件。如果存在,將會(huì)調(diào)用回調(diào)函數(shù),錯(cuò)誤(如果有)作為唯一參數(shù)。

server.address()

操作系統(tǒng)返回綁定的地址,協(xié)議族名和服務(wù)器端口。查找哪個(gè)端口已經(jīng)被系統(tǒng)綁定時(shí),非常有用。返回的對(duì)象有3個(gè)屬性,比如:{ port: 12346, family: 'IPv4', address: '127.0.0.1' }

例如:

var server = net.createServer(function (socket) {
  socket.end("goodbye\n");
});

// grab a random port.
server.listen(function() {
  address = server.address();
  console.log("opened server on %j", address);
});

'listening'事件觸發(fā)前,不要調(diào)用server.address()

server.unref()

如果這是事件系統(tǒng)中唯一一個(gè)活動(dòng)的服務(wù)器,調(diào)用unref將允許程序退出。如果服務(wù)器已被unref,則再次調(diào)用unref并不會(huì)產(chǎn)生影響。

server.ref()

unref相反,如果這是唯一的服務(wù)器,在之前被unref了的服務(wù)器上調(diào)用ref將不會(huì)讓程序退出(默認(rèn)行為)。如果服務(wù)器已經(jīng)被ref,則再次調(diào)用ref并不會(huì)產(chǎn)生影響。

server.maxConnections

設(shè)置這個(gè)選項(xiàng)后,當(dāng)服務(wù)器連接數(shù)超過(guò)數(shù)量時(shí)拒絕新連接。

一旦已經(jīng)用child_process.fork()方法將socket發(fā)送給子進(jìn)程, 就不推薦使用這個(gè)選項(xiàng)。

server.connections

已經(jīng)拋棄這個(gè)函數(shù)。請(qǐng)用server.getConnections()代替。服務(wù)器上當(dāng)前連接的數(shù)量。

當(dāng)調(diào)用child_process.fork()發(fā)送一個(gè)socket給子進(jìn)程時(shí),它將變?yōu)?code>null。 要輪詢子進(jìn)程來(lái)獲取當(dāng)前活動(dòng)連接的數(shù)量,請(qǐng)用server.getConnections代替。

server.getConnections(callback)

異步獲取服務(wù)器當(dāng)前活躍連接的數(shù)量。當(dāng)socket發(fā)送給子進(jìn)程后才有效;

回調(diào)函數(shù)有2個(gè)參數(shù)errcount。

net.Server是事件分發(fā)器EventEmitter, 有以下事件:

事件: 'listening'

當(dāng)服務(wù)器調(diào)用server.listen綁定后會(huì)觸發(fā)。

事件:'connection'

  • {Socket object} 連接對(duì)象

當(dāng)新連接創(chuàng)建后會(huì)被觸發(fā)。socketnet.Socket實(shí)例。

事件: 'close'

服務(wù)器關(guān)閉時(shí)會(huì)觸發(fā)。注意,如果存在連接,這個(gè)事件不會(huì)被觸發(fā)直到所有的連接關(guān)閉。

事件: 'error'

  • {Error Object}

發(fā)生錯(cuò)誤時(shí)觸發(fā)。'close'事件將被下列事件直接調(diào)用。請(qǐng)查看server.listen例子。

Class: net.Socket

這個(gè)對(duì)象是TCP或UNIX Socket的抽象。net.Socket實(shí)例實(shí)現(xiàn)了一個(gè)雙工流接口。他們可以在用戶創(chuàng)建客戶端(使用connect())時(shí)使用,或者由Node創(chuàng)建它們,并通過(guò)connection服務(wù)器事件傳遞給用戶。

new net.Socket([options])

構(gòu)造一個(gè)新的socket對(duì)象。

options對(duì)象有以下默認(rèn)值:

{ fd: null
  allowHalfOpen: false,
  readable: false,
  writable: false
}

參數(shù)fd允許你指定一個(gè)存在的文件描述符。將readable和(或)writable設(shè)為true,允許在這個(gè)socket上讀和(或)寫(注意,僅在參數(shù)fd有效時(shí))。關(guān)于allowHalfOpen,參見createServer()'end'事件。

socket.connect(port[, host][, connectListener])

socket.connect(path[, connectListener])

使用傳入的socket打開一個(gè)連接。如果指定了端口port和主機(jī)host,TCP socket將打開socket。如果忽略參數(shù)host,則默認(rèn)為localhost。如果指定了 path,socket將會(huì)被指定路徑的unix socket打開。

通常情況不需要使用這個(gè)函數(shù),比如使用net.createConnection打開socket。只有你實(shí)現(xiàn)了自己的socket時(shí)才會(huì)用到。

這是異步函數(shù)。當(dāng)'connect'事件被觸發(fā)時(shí),socket已經(jīng)建立。如果這是問題連接,'connect'事件不會(huì)被觸發(fā),將會(huì)拋出'error'事件。

參數(shù)connectListener將會(huì)作為監(jiān)聽器添加到'connect'事件。

socket.bufferSize

socket.bufferSize是net.Socket的一個(gè)屬性,用于socket.write()。它能夠幫助用戶獲取更快的運(yùn)行速度。計(jì)算機(jī)不能一直處于寫入大量數(shù)據(jù)狀態(tài)--網(wǎng)絡(luò)連接可能太慢。Node在內(nèi)部會(huì)將排隊(duì)數(shù)據(jù)寫入到socket,并在網(wǎng)絡(luò)可用時(shí)發(fā)送。(內(nèi)部實(shí)現(xiàn):輪詢socket的文件描述符直到變?yōu)榭蓪懀?/p>

這種內(nèi)部緩沖的缺點(diǎn)是會(huì)增加內(nèi)存使用量。這個(gè)屬性表示當(dāng)前準(zhǔn)備寫的緩沖字符數(shù)。(字符的數(shù)量等于準(zhǔn)備寫入的字節(jié)的數(shù)量,但是緩沖區(qū)可能包含字符串,這些字符串是惰性編碼的,所以準(zhǔn)確的字節(jié)數(shù)還無(wú)法知道)。

遇到很大增長(zhǎng)很快的bufferSize時(shí),用戶可用嘗試用pause()resume()來(lái)控制字符流。

socket.setEncoding([encoding])

設(shè)置socket的編碼為可讀流。更多信息參見stream.setEncoding()

socket.write(data[, encoding][, callback])

在socket上發(fā)送數(shù)據(jù)。第二個(gè)參數(shù)指定了字符串的編碼,默認(rèn)是UTF8編碼。

如果所有數(shù)據(jù)成功刷新到內(nèi)核緩沖區(qū),返回true。如果數(shù)據(jù)全部或部分在用戶內(nèi)存里,返回false。當(dāng)緩沖區(qū)為空的時(shí)候會(huì)觸發(fā)'drain'。

當(dāng)數(shù)據(jù)最終被完整寫入的的時(shí)候,可選的callback參數(shù)會(huì)被執(zhí)行,但不一定會(huì)馬上執(zhí)行。

socket.end([data][, encoding])

半關(guān)閉socket。例如,它發(fā)送一個(gè)FIN包??赡芊?wù)器仍在發(fā)送數(shù)據(jù)。

如果參數(shù)data不為空,等同于調(diào)用socket.write(data, encoding)后再調(diào)用socket.end()。

socket.destroy()

確保沒有I/O活動(dòng)在這個(gè)套接字上。只有在錯(cuò)誤發(fā)生情況下才需要。(處理錯(cuò)誤等等)。

socket.pause()

暫停讀取數(shù)據(jù)。就是說(shuō),不會(huì)再觸發(fā)data事件。對(duì)于控制上傳非常有用。

socket.resume()

調(diào)用pause()后想恢復(fù)讀取數(shù)據(jù)。

socket.setTimeout(timeout[, callback])

socket閑置時(shí)間超過(guò)timeout毫秒后 ,將socket設(shè)置為超時(shí)。

觸發(fā)空閑超時(shí)事件時(shí),socket將會(huì)收到'timeout'事件,但是連接不會(huì)被斷開。用戶必須手動(dòng)調(diào)用end()destroy()這個(gè)socket。

如果timeout= 0,那么現(xiàn)有的閑置超時(shí)會(huì)被禁用

可選的callback參數(shù)將會(huì)被添加成為'timeout'事件的一次性監(jiān)聽器。

socket.setNoDelay([noDelay])

禁用納格(Nagle)算法。默認(rèn)情況下TCP連接使用納格算法,在發(fā)送前他們會(huì)緩沖數(shù)據(jù)。將noDelay設(shè)置為true將會(huì)在調(diào)用socket.write()時(shí)立即發(fā)送數(shù)據(jù)。noDelay默認(rèn)值為true。

socket.setKeepAlive([enable][, initialDelay])

禁用/啟用長(zhǎng)連接功能,并在發(fā)送第一個(gè)在閑置socket上的長(zhǎng)連接 probe 之前,可選地設(shè)定初始延時(shí)。默認(rèn)為false。

設(shè)定initialDelay(毫秒),來(lái)設(shè)定收到的最后一個(gè)數(shù)據(jù)包和第一個(gè)長(zhǎng)連接probe之間的延時(shí)。將initialDelay設(shè)為0,將會(huì)保留默認(rèn)(或者之前)的值。默認(rèn)值為0。

socket.address()

操作系統(tǒng)返回綁定的地址,協(xié)議族名和服務(wù)器端口。返回的對(duì)象有3個(gè)屬性,比如{ port: 12346, family: 'IPv4', address: '127.0.0.1' }

socket.unref()

如果這是事件系統(tǒng)中唯一一個(gè)活動(dòng)的服務(wù)器,調(diào)用unref將允許程序退出。如果服務(wù)器已被unref,則再次調(diào)用unref并不會(huì)產(chǎn)生影響。

socket.ref()

unref相反,如果這是唯一的服務(wù)器,在之前被unref了的服務(wù)器上調(diào)用ref將不會(huì)讓程序退出(默認(rèn)行為)。如果服務(wù)器已經(jīng)被ref,則再次調(diào)用ref并不會(huì)產(chǎn)生影響。

socket.remoteAddress

遠(yuǎn)程的IP地址字符串,例如:'74.125.127.100'或者'2001:4860:a005::68'。

socket.remoteFamily

遠(yuǎn)程IP協(xié)議族字符串,比如'IPv4'或者'IPv6'。

socket.remotePort

遠(yuǎn)程端口,數(shù)字表示,例如:80或者21。

socket.localAddress

網(wǎng)絡(luò)連接綁定的本地接口遠(yuǎn)程客戶端正在連接的本地IP地址,字符串表示。例如,如果你在監(jiān)聽'0.0.0.0'而客戶端連接在'192.168.1.1',這個(gè)值就會(huì)是 '192.168.1.1'。

socket.localPort

本地端口地址,數(shù)字表示。例如:80或者21。

socket.bytesRead

接收到得字節(jié)數(shù)。

socket.bytesWritten

發(fā)送的字節(jié)數(shù)。

net.Socket是事件分發(fā)器EventEmitter的實(shí)例, 有以下事件:

事件: 'lookup'

在解析域名后,但在連接前,觸發(fā)這個(gè)事件。對(duì)UNIX sokcet不適用。

  • err {Error | Null} 錯(cuò)誤對(duì)象。參見dns.lookup().
  • address {String} IP地址。
  • family {String | Null} 地址類型。參見dns.lookup().

事件: 'connect'

當(dāng)成功建立socket連接時(shí)觸發(fā)。參見connect()。

事件: 'data'

  • {Buffer object}

當(dāng)接收到數(shù)據(jù)時(shí)觸發(fā)。參數(shù)data可以是BufferString。使用socket.setEncoding()設(shè)定數(shù)據(jù)編碼。(更多信息參見Readable Stream)。

當(dāng)Socket觸發(fā)一個(gè)'data'事件時(shí),如果沒有監(jiān)聽器,數(shù)據(jù)將會(huì)丟失。

事件: 'end'

當(dāng)socket另一端發(fā)送FIN包時(shí),觸發(fā)該事件。

默認(rèn)情況下(allowHalfOpen == false),一旦socket將隊(duì)列里的數(shù)據(jù)寫完畢,socket將會(huì)銷毀它的文件描述符。如果allowHalfOpen == true,socket不會(huì)從它這邊自動(dòng)調(diào)用end(),使的用戶可以隨意寫入數(shù)據(jù),而讓用戶端自己調(diào)用end()。

事件: 'timeout'

當(dāng)socket空閑超時(shí)時(shí)觸發(fā),僅是表明socket已經(jīng)空閑。用戶必須手動(dòng)關(guān)閉連接。

參見:socket.setTimeout()

事件: 'drain'

當(dāng)寫緩存為空得時(shí)候觸發(fā)??捎脕?lái)控制上傳。

參見:socket.write()的返回值。

事件: 'error'

  • {Error object}

錯(cuò)誤發(fā)生時(shí)觸發(fā)。以下事件將會(huì)直接觸發(fā)'close'事件。

事件: 'close'

  • had_error {Boolean} 如果socket傳輸錯(cuò)誤,為true

當(dāng)socket完全關(guān)閉時(shí)觸發(fā)。參數(shù)had_error是boolean,它表示是否因?yàn)閭鬏斿e(cuò)誤導(dǎo)致socket關(guān)閉。

net.isIP(input)

測(cè)試是否輸入的為IP地址。字符串無(wú)效時(shí)返回0。IPV4情況下返回4,IPV6情況下返回6.

net.isIPv4(input)

如果輸入的地址為IPV4,返回true,否則返回false。

net.isIPv6(input)

如果輸入的地址為IPV6,返回true,否則返回false。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)