nodeJS之TCP模塊net
TCP服務在網絡應用中十分常見,目前大多數的應用都是基於TCP搭建而成的。net模塊提供了一個異步網絡包裝器,用於TCP網絡編程,它包含了創建服務器和客戶端的方法。本文將詳細介紹nodeJS中的net模塊
IP測試
【net.isIP(input)】
測試是否輸入的為 IP 地址。字符串無效時返回 0。 IPV4 情況下返回 4, IPV6情況下返回 6
var net = require(‘net‘); console.log(net.isIP(‘1.1.1.1‘));//4console.log(net.isIP(‘1.1‘));//0console.log(net.isIP(‘AD80::ABAA:0000:00C2:0002‘));//6
【net.isIPv4(input)】
如果輸入的地址為 IPV4, 返回 true,否則返回 false
var net = require(‘net‘); console.log(net.isIPv4(‘1.1.1.1‘));//trueconsole.log(net.isIPv4(‘1.1‘));//false
【net.isIPv6(input)】
如果輸入的地址為 IPV6, 返回 true,否則返回 false
var net = require(‘net‘); console.log(net.isIPv6(‘1.1.1.1‘));//trueconsole.log(net.isIPv6(‘AD80::ABAA:0000:00C2:0002‘));//true
服務器
【net.createServer([options][, connectionListener])】
創建一個 TCP 服務器,參數如下
options allowHalfOpen: false(默認),如果為true,當另一端socket發送FIN包時socket不會自動發送FIN包。socket變為不可讀但可寫(半關閉) pauseOnConnect: false(默認),如果為true,當連接到來的時候相關聯的socket將會暫停。它允許在初始進程不讀取數據情況下,讓連接在進程間傳遞。調用resume()從暫停的socket裏讀取數據 connectionListener 自動給 ‘connection‘ 事件創建監聽器
var server = net.createServer(function() { });
【server.listen(port[, host][, backlog][, callback])】
開始接受指定端口port和主機host的連接。如果忽略主機host,服務器將會接受任何IPv4地址(INADDR_ANY)的直接連接。端口為0,則會分配一個隨機端口
積壓量(Backlog)為連接等待隊列的最大長度。實際長度由操作系統通過sysctl設定,比如linux上的tcp_max_syn_backlog和somaxconn。這個參數默認值是511
當服務器被綁定時會觸發‘listening‘事件。最後一個參數callback將會作為‘listening‘事件的監聽器
有些用戶會遇到EADDRINUSE錯誤,它表示另外一個服務器已經運行在所請求的端口上。處理這個情況的辦法是等一段時間後再重試
server.listen(6000);
【server.close([callback])】
服務器停止接收新的連接,保持現有連接。當所有連接結束的時候服務器會關閉,並會觸發‘close‘事件。你可以傳一個回調函數來監聽‘close‘事件。如果存在,將會調用回調函數,錯誤(如果有)作為唯一參數
【server.address()】
操作系統返回綁定的地址、協議族名和服務器端口。查找哪個端口已經被系統綁定時,非常有用
[註意]在 ‘listening‘ 事件觸發前,不要調用 server.address()
server.listen(function() { //{ address: ‘::‘, family: ‘IPv6‘, port: 53806 } console.log(server.address()); });
【server.maxConnections】
設置這個選項後,當服務器連接數超過數量時拒絕新連接
一旦已經用 child_process.fork() 方法將 socket 發送給子進程, 就不推薦使用這個選項
【server.getConnections(callback)】
異步獲取服務器當前活躍連接的數量。當 socket 發送給子進程後才有效;
回調函數有 2 個參數 err 和 count
server.getConnections(function(err,count){ console.log(count);//0})
【事件listening】
當服務器調用 server.listen 綁定後會觸發
【事件connection】
{Socket object} 連接對象
當新連接創建後會被觸發。socket 是 net.Socket實例
【事件close】
服務器關閉時會觸發
[註意]如果存在連接,這個事件不會被觸發直到所有的連接關閉
【事件error】
發生錯誤時觸發
客戶端
【net.connect(options[, connectionListener])】
【net.createConnection(options[, connectionListener])】
connect()的別名是createConnection()方法
該方法返回一個新的 ‘net.Socket‘,並連接到指定的地址和端口。當 socket 建立的時候,將會觸發 ‘connect‘ 事件。和‘net.Socket‘有相同的方法
對於 TCP sockets,參數options如下
port: 客戶端連接到 Port 的端口(必須) host: 客戶端要連接到得主機。默認 ‘localhost‘localAddress: 網絡連接綁定的本地接口 localPort: 網絡連接綁定的本地端口 family : IP 棧版本。默認 4
對於本地域socket,參數options如下
path: 客戶端連接到得路徑(必須)
var client = net.connect({port: 5000}, function() {});
Socket
【new net.Socket([options])】
構造一個新的 socket 對象
options 對象有以下默認值:
{ fd: null allowHalfOpen: false, readable: false, writable: false}
參數fd允許指定一個存在的文件描述符。將readable和(或)writable設為true,允許在這個socket上讀或寫(僅在參數fd有效時)
【socket.connect(port[, host][, connectListener])】
【socket.connect(path[, connectListener])】
使用傳入的socket打開一個連接。如果指定了端口port和主機host,TCP socket將打開socket。如果忽略參數host,則默認為localhost。如果指定了path,socket將會被指定路徑的unix socket 打開
參數 connectListener 將會作為監聽器添加到 ‘connect‘ 事件
【socket.write(data[, encoding][, callback])】
在socket上發送數據。第二個參數指定了字符串的編碼,默認是UTF8編碼
如果所有數據成功刷新到內核緩沖區,返回true。如果數據全部或部分在用戶內存裏,返回false。當緩沖區為空的時候會觸發‘drain‘
當數據最終被完整寫入的的時候,可選的callback參數會被執行,但不一定會馬上執行
【socket.end([data][, encoding])】
半關閉socket。例如,它發送一個FIN包。可能服務器仍在發送數據。
如果參數data不為空,等同於調用socket.write(data,encoding)後再調用socket.end()
【socket.destroy()】
確保沒有 I/O 活動在這個套接字上。只有在錯誤發生情況下才需要
【socket.pause()】
暫停讀取數據。就是說,不會再觸發 data 事件。對於控制上傳非常有用
【socket.resume()】
調用 pause() 後想恢復讀取數據
【socket.setTimeout(timeout[, callback])】
socket 閑置時間超過 timeout 毫秒後 ,將 socket 設置為超時。觸發空閑超時事件時,socket 將會收到 ‘timeout‘事件,但是連接不會被斷開。用戶必須手動調用 end() 或 destroy() 這個socket。
如果 timeout = 0, 那麽現有的閑置超時會被禁用。可選的 callback 參數將會被添加成為 ‘timeout‘ 事件的一次性監聽器
【socket.setNoDelay([noDelay])】
禁用納格(Nagle)算法。默認情況下 TCP 連接使用納格算法,在發送前他們會緩沖數據。將 noDelay 設置為 true 將會在調用 socket.write() 時立即發送數據。noDelay 默認值為 true
【socket.setKeepAlive([enable][, initialDelay])】
禁用/啟用長連接功能,在發送第一個在閑置socket上的長連接probe之前,可選地設定初始延時。默認false
設定initialDelay(毫秒),來設定收到的最後一個數據包和第一個長連接probe之間的延時。將 initialDelay 設為0,將會保留默認(或者之前)的值。默認值為0
【socket.address()】
操作系統返回綁定的地址,協議族名和服務器端口。返回的對象有 3 個屬性,比如{ port: 12346, family: ‘IPv4‘, address: ‘127.0.0.1‘ }
【socket.remoteAddress】
遠程的 IP 地址字符串
【socket.remoteFamily】
遠程IP協議族字符串
【socket.remotePort】
遠程端口,數字表示
【socket.localAddress】
遠程客戶端正在連接的本地IP地址,字符串表示
【socket.localPort】
本地端口地址,數字表示
【socket.bytesRead】
接收的字節數
【socket.bytesWritten】
發送的字節數
【事件lookup】
在解析域名後,但在連接前,觸發這個事件。對 UNIX sokcet 不適用
err {Error | Null} 錯誤對象 address {String} IP 地址。 family {String | Null} 地址類型
【事件connect】
當成功建立 socket 連接時觸發、
【事件data】
{Buffer object}
當接收到數據時觸發。參數 data 可以是 Buffer 或 String
當 Socket 觸發一個 ‘data‘ 事件時,如果沒有監聽器,數據將會丟失
【事件end】
當 socket 另一端發送 FIN 包時,觸發該事件
【事件timeout】
當 socket 空閑超時時觸發,僅是表明 socket 已經空閑。用戶必須手動關閉連接
【事件drain】
當寫緩存為空得時候觸發。可用來控制上傳
【事件error】
錯誤發生時觸發
【事件close】
had_error {Boolean} 如果 socket 傳輸錯誤,為 true
當 socket 完全關閉時觸發。參數 had_error 是 boolean,它表示是否因為傳輸錯誤導致 socket 關閉
簡易服務器
【服務器】
//server.jsvar net = require(‘net‘) ;var server = net.createServer(function(socket) { socket.write("Hi!\n"); socket.on("data", function(data) { console.log(data.toString()); }); socket.on("end", function() { console.log(‘有客戶機下線了!!!‘); }); socket.on(‘error‘, function() { console.log(‘發生意外錯誤!!!‘); }); }) ; server.listen(8080) ;
【客戶機】
//client.jsvar net = require(‘net‘) ;var client = net.connect({port: 8080},function(){ client.name = ‘客戶機1‘; client.write(client.name + ‘ 上線了!\n‘); client.end(client.name + ‘ 下線了!\n‘); client.on("data", function(data) { console.log(data.toString()); }); });
簡易聊天室
【服務器】
//chatServer.jsvar net = require(‘net‘);var i = 0;//保存客戶機var clientList = [];var server = net.createServer(function(socket) { socket.name = ‘用戶‘ + (++i); socket.write(‘【聊天室提示】歡迎‘ + socket.name + ‘\n‘); //更新客戶機數組 clientList.push(socket); function showClients(){ console.log(‘【當前在線用戶】:‘); for(var i=0;i<clientList.length;i++) { console.log(clientList[i].name); } } showClients(); socket.on("data", function(data) { //把當前連接的客戶機的信息轉發到其他客戶機 for(var i=0;i<clientList.length;i++) { if(socket !== clientList[i]) { clientList[i].write(‘【‘ + socket.name + ‘】:‘ + data); } } }); socket.on("close", function() { //當前客戶機下線時,將其從客戶機數組中移除 clientList.splice(clientList.indexOf(socket), 1); showClients(); }); socket.on(‘error‘, function(err) { console.log(socket.name + ‘退出‘); }); }); server.listen(8080) ;
【客戶機】
//chatClient.jsvar net = require(‘net‘); process.stdin.resume(); process.stdin.setEncoding(‘utf8‘);var client = net.connect({port: 8080},function(){ console.log(‘【本機提示】登錄到聊天室‘); process.stdin.on(‘data‘,function(data){ client.write(data); }) client.on("data", function(data) { console.log(data.toString()); }); client.on(‘end‘, function() { console.log(‘【本機提示】退出聊天室‘); process.exit(); }); client.on(‘error‘, function() { console.log(‘【本機提示】聊天室異常‘); process.exit(); }); });
nodeJS之TCP模塊net