### 穩定度: 2 - 穩定
`net`模塊為你提供了異步的網絡調用的包裝。它同時包含了創建服務器和客戶端的函數。你可以通過`require('net')`來引入這個模塊。
#### net.createServer([options][, connectionListener])
創建一個新的TCP服務器。`connectionListener`參數會被自動綁定為`connection`事件的監聽器。
`options`是一個包含下列默認值的對象:
~~~
{
allowHalfOpen: false,
pauseOnConnect: false
}
~~~
如果`allowHalfOpen`是`true`,那么當另一端的`socket`發送一個`FIN`報文時`socket`并不會自動發送`FIN`報文。`socket`變得不可讀,但是可寫。你需要明確地調用`end()`方法。詳見`end`事件。
如果`pauseOnConnect`是true,那么`socket`在每一次被連接時會暫停,并且不會讀取數據。這允許在進程間被傳遞的連接不讀取任何數據。如果要讓一個被暫停的`socket`開始讀取數據,調用`resume()`方法。
以下是一個應答服務器的例子,監聽8124端口:
~~~
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`測試:
~~~
telnet localhost 8124
~~~
想要監聽`socket``/tmp/echo.sock`,只需改變倒數第三行:
~~~
server.listen('/tmp/echo.sock', function() { //'listening' listener
~~~
使用`nc`連接一個UNIX domain socket服務器:
~~~
nc -U /tmp/echo.sock
~~~
#### net.connect(options[, connectionListener])
#### net.createConnection(options[, connectionListener])
工廠函數,返回一個新的`net.Socket`實例,并且自動使用提供的`options`進行連接。
`options`會被同時傳遞給`net.Socket`構造函數和`socket.connect`方法。
參數`connectListener`將會被立即添加為`connect`事件的監聽器。
下面是一個上文應答服務器的客戶端的例子:
~~~
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`只需要改變第二行為:
~~~
var client = net.connect({path: '/tmp/echo.sock'});
~~~
#### net.connect(port[, host][, connectListener])
#### net.createConnection(port[, host][, connectListener])
工廠函數,返回一個新的`net.Socket`實例,并且自動使用指定的端口(port)和主機(host)進行連接。
如果`host`被省略,默認為`localhost`。
參數`connectListener`將會被立即添加為`connect`事件的監聽器。
#### net.connect(path[, connectListener])
#### net.createConnection(path[, connectListener])
工廠函數,返回一個新的unix`net.Socket`實例,并且自動使用提供的路徑(path)進行連接。
參數`connectListener`將會被立即添加為`connect`事件的監聽器。
#### Class: net.Server
這個類用于創建一個TCP或本地服務器。
#### server.listen(port[, hostname][, backlog][, callback])
開始從指定端口和主機名接收連接。如果省略主機名,那么如果IPv6可用,服務器會接受從任何IPv6地址(::)來的鏈接,否則為任何IPv4地址(0.0.0.0)。如果端口為0那么將會為其設置一個隨機端口。
積壓量`backlog`是連接等待隊列的最大長度。實際長度由你的操作系統的`sysctl`設置決定(如linux中的`tcp_max_syn_backlog`和`somaxconn`)。這個參數的默認值是511(不是512)。
這個函數式異步的。當服務器綁定了指定端口后,`listening`事件將會被觸發。最后一個參數`callback`將會被添加為`listening`事件的監聽器。
有些用戶可能遇到的情況是收到`EADDRINUSE`錯誤。這意味著另一個服務器已經使用了該端口。一個解決的辦法是等待一段時間后重試。
~~~
server.on('error', function (e) {
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
server.close();
server.listen(PORT, HOST);
}, 1000);
}
});
~~~
(注意,`io.js`中所有的`socket`都已經設置了`SO_REUSEADDR`)
#### server.listen(path[, callback])
- path String
- callback Function
啟動一個本地`socket`服務器,監聽指定路徑(`path`)上的連接。
這個函數式異步的。當服務器監聽了指定路徑后,`listening`事件將會被觸發。最后一個參數`callback`將會被添加為`listening`事件的監聽器。
在UNIX中,`local domain`經常被稱作`UNIX domain`。`path`是一個文件系統路徑名。它在被創建時會受相同文件名約定(same naming conventions)的限制并且進行權限檢查(permissions checks)。它在文件系統中可見,并且在被刪除前持續存在。
在Windows中,`local doamin`使用一個命名管道(named pipe)實現。`path`必須指向`\\?\pipe\`或`\\.\pipe\.`中的一個條目,但是后者可能會做一些命名管道的處理,如處理`..`序列。除去表現,命名管道空間是平坦的(flat)。管道不會持續存在,它們將在最后一個它們的引用關閉后被刪除。不要忘記,由于`JavaScript`的字符串轉義,你必須在指定`path`時使用雙反斜杠:
~~~
net.createServer().listen(
path.join('\\\\?\\pipe', process.cwd(), 'myctl'))
~~~
#### server.listen(handle[, callback])
- handle Object
- callback Function
`handle`對象可以被設置為一個服務器或一個`socket`(或者任意以下劃線開頭的成員`_handle`),或者一個`{fd: <n>}`對象。
這將使得服務器使用指定句柄接受連接,但它假設文件描述符或句柄已經被綁定至指定的端口或域名`socket`。
在Windows下不支持監聽一個文件描述符。
這個函數式異步的。當服務器已被綁定后,`listening`事件將會被觸發。最后一個參數`callback`將會被添加為`listening`事件的監聽器。
#### server.listen(options[, callback])
-
**options Object**
- port Number 可選
- host String 可選
- backlog Number 可選
- path String 可選
- exclusive Boolean 可選
-
callback Function 可選
`port`,`host`和`backlog`屬性,以及可選的`callback`函數,與`server.listen(port, [host], [backlog], [callback])`中表現一致。`path`可以被指定為一個UNIX `socket`。
如果`exclusive`是`false`(默認),那么工作集群(cluster workers)將會使用相同的底層句柄,處理的連接的職責將會被它們共享。如果`exclusive`是`true`,那么句柄是不被共享的,企圖共享將得到一個報錯的結果。下面是一個監聽獨有端口的例子:
~~~
server.listen({
host: 'localhost',
port: 80,
exclusive: true
});
~~~
#### server.close([callback])
使服務器停止接收新的連接并且保持已存在的連接。這個函數式異步的,當所有的連接都結束時服務器會最終關閉,并處罰一個`close`事件。可選的,你可以傳遞一個回調函數來監聽`close`事件。如果傳遞了,那么它的唯一的第一個參數將表示任何可能潛在發生的錯誤。
#### server.address()
返回服務器綁定的地址,協議族名和端口通過操作系統報告。對查找操作系統分配的地址哪個端口被分配非常有用。返回一個有三個屬性的對象。如`{ 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`事件觸發前,不要調用`server.address()`方法。
#### server.unref()
調用一個`server`對象的`unref`方法將允許如果它是事件系統中唯一活躍的服務器,程序將會退出。如果服務器已經被調用過這個方法,那么再次調用這個方法將不會有任何效果。
返回`server`對象。
#### server.ref()
與`unref`相反,在一個已經被調用`unref`方法的`server`中調用`ref`方法,那么如果它是唯一活躍的服務器時,程序將不會退出(默認)。如果服務器已經被調用過這個方法,那么再次調用這個方法將不會有任何效果。
返回`server`對象。
#### server.maxConnections
設置了這個屬性后,服務器的連接數達到時將會開始拒絕連接。
一旦`socket`被使用`child_process.fork()`傳遞給了子進程,這個屬性就不被推薦去設置。
#### server.connections
這個函數已經被棄用。請使用`server.getConnections()`替代。
服務器的當前連接數。
當使用`child_process.fork()`傳遞一個`socket`給子進程時,這個屬性將變成`null`。想要得到正確的結果請使用`server.getConnections`。
#### server.getConnections(callback)
異步地去獲取服務器的當前連接數,在`socket`被傳遞給子進程時仍然可用。
回調函數的兩個參數是`err`和`count`。
### `net.Server`是一個具有以下事件的`EventEmitter`:
#### Event: 'listening'
當調用`server.listen`后,服務器已被綁定時觸發。
#### Event: 'connection'
- Socket object 連接對象
當新的連接產生時觸發。`socket`是一個`net.Socket`實例。
#### Event: 'close'
當服務器關閉時觸發。注意如果服務器中仍有連接存在,那么這個事件會直到所有的連接都關閉后才觸發。
#### Event: 'error'
- Error Object
當發生錯誤時觸發。`close`事件將會在它之后立即觸發。參閱`server.listen`。
#### Class: net.Socket
這個對象是一個TCP或本地`socket`的抽象。`net.Socket`實例實現了雙工流(duplex Stream)接口。它可以被使用者創建,并且被作為客戶端(配合`connect()`)使用。或者也可以被`io.js`創建,并且通過服務器的`connection`事件傳遞給使用者。
#### new net.Socket([options])
創建一個新的`socket`對象。
`options`是一個有以下默認值的對象:
~~~
{ fd: null
allowHalfOpen: false,
readable: false,
writable: false
}
~~~
`fd`允許你使用一個指定的已存在的`socket`文件描述符。設置`readable` 和/或 `writable`為`true`將允許從這個`socket`中讀 和/或 寫(注意,僅在傳遞了`passed`時可用)。關于`allowHalfOpen`,參閱`createServer()`和`end`事件。
#### socket.connect(options[, connectListener])
從給定的`socket`打開一個連接。
對于TCP`socket`,`options`參數需是一個包含以下屬性的對象:
-
port: 客戶端需要連接的端口(必選)。
-
host: 客戶端需要連接的主機(默認:'localhost')
-
localAddress: 將要綁定的本地接口,為了網絡連接。
-
localPort: 將要綁定的本地端口,為了網絡連接。
-
family : IP協議族版本,默認為`4`。
-
lookup : 自定義查找函數。默認為`dns.lookup`。
對于本地domain `socket`,`options`參數需是一個包含以下屬性的對象:
- path: 客戶端需要連接的路徑(必選)。
通常這個方法是不需要的,因為通過`net.createConnection`打開`socket`。只有在你自定義了`socket`時才使用它。
這個函數式異步的,當`connect`事件觸發時,這個`socket`就被建立了。如果在連接的過程有問題,那么`connect`事件將不會觸發,`error`將會帶著這個異常觸發。
`connectListener`參數會被自動添加為`connect`事件的監聽器。
#### socket.connect(port[, host][, connectListener])
#### socket.connect(path[, connectListener])
參閱`socket.connect(options[, connectListener])`。
#### socket.bufferSize
`net.Socket`的屬性,用于`socket.write()`。它可以幫助用戶獲取更快的運行速度。計算機不能一直保持大量數據被寫入`socket`的狀態,網絡連接可以很慢。`io.js`在內部會排隊等候數據被寫入`socekt`并確保傳輸連接上的數據完好。 (內部實現為:輪詢`socekt`的文件描述符等待它為可寫)。
內部緩存的可能結果是內存使用會增長。這個屬性展示了緩存中還有多少待寫入的字符(字符的數目約等于要被寫入的字節數,但是緩沖區可能包含字符串,而字符串是惰性編碼的,所以確切的字節數是未知的)。
遇到數值很大或增長很快的`bufferSize`時,應當嘗試使用`pause()`和`resume()`來控制。
#### socket.setEncoding([encoding])
設置`socket`的編碼作為一個可讀流。詳情參閱`stream.setEncoding()`。
#### socket.write(data[, encoding][, callback])
在套接字上發送數據。第二個參數指定了字符串的編碼,默認為UTF8。
如果所有數據成功被刷新至了內核緩沖區,則返回`true`。如果所有或部分數據仍然在用戶內存中排隊,則返回`false`。`drain`事件將會被觸發當`buffer`再次為空時。
當數據最終被寫入時,`callback`回調函數將會被執行,但可能不會馬上執行。
#### socket.end([data][, encoding])
半關閉一個`socket`。比如,它發送一個`FIN`報文。可能服務器仍然在發送一些數據。
如果`data`參數被指定,那么等同于先調用`socket.write(data, encoding)`,再調用`socket.end()`。
#### socket.destroy()
確保這個`socket`上沒有I/O活動發生。只在發生錯誤情況才需要(如處理錯誤)。
#### socket.pause()
暫停數據讀取。`data`事件將不會再觸發。對于控制上傳非常有用。
#### socket.resume()
用于在調用`pause()`后,恢復數據讀取。
#### socket.setTimeout(timeout[, callback])
如果`socket`在`timeout`毫秒中沒有活動后,設置其為超時。默認情況下,`net.Socket`沒有超時。
當超時發生,`socket`會收到一個`timeout`事件,但是連接將不會被斷開。用戶必須手動地調用`end()`或`destroy()`方法。
如果`timeout`是`0`,那么現有的超時將會被禁用。
可選的`callback`參數就會被自動添加為`timeout`事件的監聽器。
返回一個`socket`。
#### socket.setNoDelay([noDelay])
警用納格算法(Nagle algorithm)。默認情況下TCP連接使用納格算法,它們的數據在被發送前會被緩存。設置`noDelay`為`true`將會在每次`socket.write()`時立刻發送數據。`noDelay`默認為`true`。
返回一個`socket`。
#### socket.setKeepAlive([enable][, initialDelay])
啟用/警用長連接功能,并且在第一個在閑置`socket`的長連接`probe`被發送前,可選得設置初始延時。`enable`默認為`false`。
設定`initialDelay`(毫秒),來設定在收到的最后一個數據包和第一個長連接`probe`之間的延時。將`initialDelay`設成`0`會讓值保持不變(默認值或之前所設的值)。默認為`0`。
返回一個`socket`。
#### socket.address()
返回綁定的地址,協議族名和端口通過操作系統報告。對查找操作系統分配的地址哪個端口被分配非常有用。返回一個有三個屬性的對象。如`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`。
#### socket.unref()
調用一個`socket`對象的`unref`方法將允許如果它是事件系統中唯一活躍的`socket`,程序將會退出。如果`socket`已經被調用過這個方法,那么再次調用這個方法將不會有任何效果。
返回`socket`對象。
#### socket.ref()
與`unref`相反,在一個已經被調用`unref`方法的`socket`中調用`ref`方法,那么如果它是唯一活躍的`socket`時,程序將不會退出(默認)。如果`socket`已經被調用過這個方法,那么再次調用這個方法將不會有任何效果。
返回`socket`對象。
#### socket.remoteAddress
遠程IP地址字符串。例如,`'74.125.127.100'`或`'2001:4860:a005::68'`。
#### socket.remoteFamily
遠程IP協議族字符串。例如,`'IPv4'`或`'IPv6'`。
#### socket.remotePort
遠程端口數值。例如,`80`或`21`。
#### socket.localAddress
遠程客戶端正連接的本地IP地址字符串。例如,如果你正在監聽`'0.0.0.0'`并且客戶端連接在`'192.168.1.1'`,其值將為`'192.168.1.1'`。
#### socket.localPort
本地端口數值。例如,`80`或`21`。
#### socket.bytesRead
接受的字節數。
#### socket.bytesWritten
發送的字節數。
### net.Socket `net.Socket`實例是一個包含以下事件的`EventEmitter`:
#### Event: 'lookup'
在解析主機名后,連接主機前觸發。對UNIX `socket`不適用。
- err {Error | Null} 錯誤對象,參閱 `dns.lookup()`
- address {String} IP地址
- family {String | Null} 地址類型。參閱'dns.lookup()`
#### Event: 'connect'
在`socket`連接成功建立后觸發。參閱`connect()`。
#### Event: 'data'
- Buffer object
在接受到數據后觸發。參數將會是一個`Buffer`或一個字符串。數據的編碼由`socket.setEncoding()`設置(更多詳細信息請查看可讀流章節)。
注意,當`socket`觸發`data`事件時,如果沒有監聽器存在。那么數據將會丟失。
#### Event: 'end'
當另一端的`socket`發送一個`FIN`報文時觸發。
默認情況(`allowHalfOpen == false`)下,一旦一個`socket`的文件描述符被從它的等待寫隊列(pending write queue)中寫出,`socket`會銷毀它。但是,當設定`allowHalfOpen == true`后,`socket`不會在它這邊自動調用`end()`,允許用戶寫入任意數量的數據,需要注意的是用戶需要在自己這邊調用`end()`。
#### Event: 'timeout'
當`socket`因不活動而超時時觸發。這只是來表示`socket`被限制。用戶必須手動關閉連接。
參閱`socket.setTimeout()`。
#### Event: 'drain'
當寫緩沖為空時觸發。可以被用來控制上傳流量。
參閱`socket.write()`的返回值。
#### Event: 'error'
- Error object
當發生錯誤時觸發。`close`事件會緊跟著這個事件觸發。
#### Event: 'close'
- had_error 如果`socket`有一個傳輸錯誤時為`true`
當`socket`完全關閉時觸發。參數`had_error`是一個表示`socket`是否是因為傳輸錯誤而關閉的布爾值。
#### net.isIP(input)
測試`input`是否是一個IP地址。如果是不合法字符串時,會返回`0`。如果是IPv4地址則返回`4`,是IPv6地址則返回`6`。
#### net.isIPv4(input)
如果`input`是一個IPv4地址則返回`true`,否則返回`false`。
#### net.isIPv6(input)
如果`input`是一個IPv6地址則返回`true`,否則返回`false`。