Node.js開發入門—通訊端(socket)編程
Node.js的net模組提供了socket編程介面,方便我們利用較為底層的通訊端介面來實現應用協議。這次我們看一個簡單的回顯伺服器樣本,包括服務端和用戶端的代碼。
使用JavaScript也可以進行通訊端編程,哈哈,這酸爽!
代碼
分伺服器和用戶端兩部分來說吧。
echoServer程式碼分析
echoServer.js:
var net = require(net);// server is an instance of net.Server// sock is an instance of net.Socketvar server = net.createServer(function(sock){ console.log('client connected, address - ', sock.remoteAddress, ' port - ', sock.remotePort); sock.setEncoding('utf8'); sock.on('data', function(data){ console.log('got data from client - ', data); sock.write(data); }); sock.on('end', function(){ console.log('client disconnected'); }); sock.on('error', function(err){ console.log('socket error - ', err); });});server.maxConnections = 10;server.listen(7, function(){ console.log('echo server bound at port - 7');});
net模組api在這裡:https://nodejs.org/api/net.html。
我使用net.createServer來建立一個伺服器執行個體,這個方法的傳回值是一個net.Server執行個體,net.Server提供了listen方法,讓我們監聽到某個連接埠上來接受用戶端串連,同時還提供了一些屬性,比如maxConnections可以設定伺服器的並發串連數上限(當伺服器的串連數超過這個值時,後續串連就會被拒掉),還有其它的,看文檔吧:https://nodejs.org/api/net.html#net_class_net_server。
net.Server還提供了一些事件,比如error、connection等。當有用戶端串連被接受時,會發射connection事件,這個事件帶一個net.Socket對象作為參數,可以在回呼函數裡訪問這個net.Socket執行個體來與用戶端互動。我在代碼裡,給createServer方法傳入了一個callback來處理connection事件,實際上也可以略作修改,通過監聽connection事件的方法處理用戶端串連。新代碼如下:
var net = require(net);var server = net.createServer();server.on('connection', function(sock){ console.log('client connected, address - ', sock.remoteAddress, ' port - ', sock.remotePort); sock.setEncoding('utf8'); sock.on('data', function(data){ console.log('got data from client - ', data); sock.write(data); }); sock.on('end', function(){ console.log('client disconnected'); }); sock.on('error', function(err){ console.log('socket error - ', err); });});server.maxConnections = 10;server.listen(7, function(){ console.log('echo server bound at port - 7');});
效果是一樣的。
net.Socket對象有一些方法,比如write可以寫資料。還有一些事件,比如error、end、data等,看代碼就能明白用法。還有一些屬性,比如remoteAddress、remotePort。
我處理了data事件,data事件有一個參數,代表讀到的資料。我在回調中直接使用net.Socket.write把資料原封不動發還給用戶端。這是echo的一種實現。還有一種更方便的實現,就是調用net.Socket的pipe方法,Node.js net模組文檔裡提供的echoServer就是用的pipe,去看看吧。
echoClient程式碼分析
echoClient.js:
var net = require(net);var readline = require('readline');console.log('type exit or quit to quit.');// sock is an instance of net.Socketvar sock = net.connect({port: 7}, function(){ console.log('server connected'); sock.setEncoding('utf8'); sock.write('Hello Echo Server');});sock.on('data', function(data){ console.log('got data from server - ', data);});sock.on('end', function(){ console.log('client disconnected');});sock.on('error', function(err){ console.log('socket error - ', err);});sock.on('close', function(){ console.log('echo client was closed'); process.exit(0);});var rl = readline.createInterface({ input: process.stdin});function quitEcho(){ rl.close(); sock.end(); console.log('quit echo client');}rl.on('line', function(cmd){ if(cmd.indexOf('quit') == 0 || cmd.indexOf('exit') == 0){ quitEcho(); }else{ sock.write(cmd + ''); }});rl.on('SIGINT', quitEcho);
用戶端代碼稍長了一些。因為我想讓echo更像echo,就調用readline模組來從標準輸入讀取資料來發送給用戶端。readline的文檔在這裡:https://nodejs.org/api/readline.html。正如它的名字,Readline可以讓你一行一行的讀取一個流。比較常見的就是讀取標準輸入資料流。Readline有一些事件,我們用到的“line”事件,在一行資料就緒時會發射,帶一個代表資料的參數。我監聽line事件,在回調中調用net.Socket的write方法寫入資料。當你在控制台輸入“quit”或“exit”時,調用quitEcho退出。
net.connect方法可以串連到指定的伺服器,它的原型如下:
net.connect(options[, connectionListener])
第一個參數是Object,用於指定和串連相關的選項,比如服務端的host、port等,如果不指定host,就預設用localhost作為服務端主機名稱。我在樣本中只指定了連接埠。
net.connect返回net.Socket對象,一旦拿到了Socket執行個體,就可以用net.Socket來為所欲為了。我監聽了data事件來接收服務端發揮的資料,監聽close事件來退出進程。net.Socket的具體API,參考https://nodejs.org/api/net.html#net_class_net_socket。
運行樣本
評書裡有句話,說時遲那時快,嗯哈,可以運行了。先執行“node echoServer.js”,然後執行“node echoClient.js”,就可以在echoClient的控制台介面輸入一些內容了。效果如: