想必咱們在用Node.js用的最多的應該是建立http服務,因此對於每一個Web開發工程師而言,Node.js的網絡相關模塊學習是必不可少。javascript
在Node.js的模塊裏面,與網絡相關的模塊有Net、DNS、HTTP、TLS/SSL、HTTPS、UDP/Datagram,除此以外,還有v8底層相關的網絡模塊有tcp_wrap.cc
、udp_wrap.cc
、pipe_wrap.cc
、stream_wrap.cc
等等,在Javascript層以及C++層之間經過process.binding
進行橋接相互通訊。java
Net模塊提供了一些用於底層的網絡通訊接口,包括建立服務器以及客戶端,其中HTTP模塊也是基於Net模型的上層封裝,在Net模塊裏面主要提供net.Server以及net.Socketnode
建立一個TCP服務器,能夠經過使用構造函數new net.Server
或者使用工廠方法net.createServer
,這兩個方法都會返回一個net.Server類,可接收兩個可選參數。算法
var net = require('net'); var server = net.createServer(function(socket){ socket .on('data',function(data){ console.log('socket data',data.toString()); socket.write( data.toString() ); }) .on('end',function(){ console.log('socket end') }) .on('error',function(error){ console.log('socket error',error); }); }); server.listen(56200,function(){ console.log('server run at ',server.address()); }); server.on('error',function(err){ throw err; }); // 執行後:server run at { address: '::', family: 'IPv6', port: 56200 }
在listen監聽的時候沒有指定端口的話會自動隨意監聽一個端口,建立完成一個TCP服務器後,使用tenlent 0.0.0.0 56200
,連接後可與服務器進行數據通訊。經過createServer
實例化一個服務後,服務會去監聽客戶端請求,與客戶端創建了連接以後會在回調裏面拋出建鏈的net.Socket
對象。緩存
建立一個TCP客戶端連接可使用構造函數new net.Socket
或者其工廠方法net.createConnection
,建立成功後都會返回一個net.Socket實例。安全
var net = require('net'); var client = net.createConnection({port:56200,host:'localhost'}); client.on('connect',function(){ console.log('client connect'); }); client.on('data',function(data){ console.log('client data',toString()); }); client.on('error',function(error){ throw error; }); client.on('close',function(){ console.log('client close'); });
socket是啥這裏就不作詳細的闡述了,下面主要了解下net.Socket
這個構造體主要有提供一些什麼方法、監聽事件的使用。服務器
connect : 當客戶端與服務端成功創建連接以後觸發,若是連接不上服務器直接拋出error事件錯誤而後退出node進程。網絡
data : 當客戶端收到服務器傳送過來的數據或者是客戶端傳送給服務器的數據的時候觸發回調。架構
end : 當另一側發送FIN包斷開的時候觸發,默認狀況下面 (allowHalfOpen == false)
socket會自我銷燬(若是寫入待處理隊列裏面還沒正式響應回包),可是咱們能夠設置allowHalfOpen
參數爲true,這樣能夠繼續往該socket裏面寫數據,可是咱們須要本身去調用 end 方法去消耗這個socket,否則可能會形成句柄泄漏。socket
close : 連接斷開的時候觸發,可是若是在傳輸的過程當中有錯誤的話這裏會在回調函數裏面拋出 error。
timeout : 當socket超時空閒的時候觸發,若是要在隊列裏面銷燬須要手動去調close方法。
lookup : 域名解析完成的時候觸發。
drain : 寫完緩存的時候觸發,可以使用在上傳大小限制中。
write() : 服務端給客戶端發送數據或者是客戶端給服務端發送數據。
address() : 獲取服務綁定的socket的IP地址,返回對象有三個屬性,分別爲端口、host以
及IPvX版本。
end() : 半關閉socket,會發送一個FIN包,服務器仍然可能發送一些數據,也能夠這樣調用socket.end(data,encoding)。
pause() : 暫停讀取數據,能夠用做對數據上傳限制。
resume() : 繼續數據讀取。
setEncoding() : 設置數據流的獲取格式。
setKeepAlive() : 容許/禁止keep-alive功能。
setNoDelay() : 禁止Nagele算法,TCP連接默認使用Nagle算法,它們在發送以前數據會被緩存。這是爲true的話在每次socket.write()的時候會當即發送數據,默認爲true。
setTimeout() : 當一個空閒的socket在多少秒後不活躍會被接受到timeout事件,可是該socket不會中止銷燬,須要手動調用end()或者destroy()。表示禁止空閒超時。
bufferSize : 當前緩存的等待被髮送的字符串的數量。
bytesRead : 收到的字節的數量。
bytesWritten : 發送的字節的數量
destroyed : 標識連接是否已經被破壞,一旦被破環,就不用使用該連接來傳輸數據。
localAddress : 遠程客戶端連接本地地址的host。若是咱們監聽服務的host是0.0.0.0,而客戶端連接的是'192.168.1.1',最後的值是後者。
localPort : 本地的端口。
remoteAddress : 客戶端IP,若是socket已是destryed的話,該值爲undefined
。
remoteFamily : 客戶端是IPvX
服務器從客戶端接受到須要處理的數據後進入處理環節,再業務邏輯處理完成以前若是socket之外斷開的話,待服務器再給客戶端回報的時候會直接響應error
事件並報錯Error : This socket has benn ended by the other part
,因此在回報以前服務端須要先判斷該socket是否被銷燬,若是沒有被銷燬則回包,若是已經斷開則銷燬:
var net = require('net'); var biz = require('./biz'); var server = net.createServer(function(socket){ socket .on('data',function(data){ biz.do(data) .then(function(){ if( !socket.destroyed ) { socket.write( data.toString() ); } else { // do some report socket.destry(); } }) .catch(function(){ !socket.destroyed && socket.end('server handler error'); }); }) .on('end',function(){ console.log('socket end') }) .on('error',function(error){ console.log('socket error',error); }); }); server.listen(56200,function(){ console.log('server run at ',server.address()); }); server.on('error',function(err){ throw err; });
對請求大小限制是服務安全裏面比不可少的一個環節,服務端不能無限大小的去接受客戶端發送過來的全部數據,而限制大小就是第一道門檻。
var net = require('net'); var MAX_REQUEST_BYTES = 2 * 1024 * 1024; // 2M var server = net.createServer(function(socket){ socket .on('data',function(data){ if(data.bytesRead > MAX_REQUEST_BYTES) { socket.pause(); socket.end('data is too big, forbidden'); // do some report } }) .on('end',function(){ console.log('socket end') }) .on('error',function(error){ console.log('socket error',error); }); }); server.listen(56200,function(){ console.log('server run at ',server.address()); }); server.on('error',function(err){ throw err; });