一、net模塊基本API
要使用Node.js的net模塊實現一個命令行聊天室,就必須先了解NET模塊的API使用。NET模塊API分爲兩大類:Server和Socket類、工廠方法。
Server類以下圖所示:
net.Server類能夠用來建立一個TCP或本地服務器,繼承了EventEmitter。
Socket類以下:
net.Socket類通常用建立一個socket客戶端或者是net.Server connection事件的參數。
工廠方法以下:
以上三個圖展現了API的使用,其實NET模塊的內部原理和C++網絡編程差很少的,都是如下步驟。
服務端:javascript
客戶端:java
以下圖所示:
編程
二、聊天室的設計和實現
上面學習了NET模塊API的使用,接下來便開始實現命令行聊天室,咱們不須要作的很複雜,只需實現以下功能便可:服務器
肯定功能以後,便開始代碼的編寫。這裏我就不一步步分析,直接上代碼了,首先是服務端:
Server:網絡
const net = require('net'); const server = net.createServer(); const clients = {};//保存客戶端的鏈接 var client = null;//當前客戶鏈接 var uid = 0; server.on('connection',(socket)=>{ //啓動心跳機制 var isOnline = !0; var keepAliveTimer = socket.timer = setInterval(()=>{ if(!isOnline){ client = socket; quit(socket.nick); return; } if(socket.writable){ isOnline = !1; socket.write('::'); }else{ client = socket; quit(socket.nick); } },3000); socket.on('end',()=>{ console.log(`client disconnected.\n\r`); socket.destroy(); }); socket.on('error',(error)=>{ console.log(error.message); }); socket.on('data',(chunk)=>{ client = socket; var msg = JSON.parse(chunk.toString()); if(msg.cmd=='keep'){ isOnline = !0; return; } dealMsg(msg); }); }); server.on('error',(err)=>{ console.log(err); }); server.on('listening',()=>{ console.log(`listening on ${server.address().address}:${server.address().port}\n\r`); }); server.listen(8060);//啓動監聽 /** * 處理用戶信息 */ function dealMsg(msg){ const cmd = msg.cmd; const funs = { 'login':login, 'chat':chat, 'quit':quit, 'exit':quit }; if(typeof funs[cmd] !== 'function') return !1; funs[cmd](msg); } /** * 釋放鏈接資源 */ function freeConn(conn){ conn.end(); delete clients[conn.uuid]; conn.timer&&clearInterval(conn.timer); } /** * 用戶首次進入聊天室 */ function login(msg){ var uuid = ''; uuid = getRndStr(15)+(++uid);//產生用戶ID client.write(`歡迎你,${msg.nick}:這裏總共有${Object.keys(clients).length}個小夥伴在聊天.\r\n`) client.nick = msg.nick; client.uuid = uuid; clients[uuid] = client; broadcast(`系統:${msg.nick}進入了聊天室.`); } /** * 廣播消息 */ function broadcast(msg){ Object.keys(clients).forEach((uuid)=>{ if((clients[uuid]!=client)& clients[uuid].writable){ clients[uuid].write(msg); } }); } /** * 退出聊天室 */ function quit(nick){ var message = `小夥伴${nick}退出了聊天室.`; broadcast(message); freeConn(client); } function chat(msg){ if(msg.msg.toLowerCase()=='quit'||msg.msg.toLowerCase()=='exit'){ quit(msg.nick); return ; } var message = `${msg.nick}說:${msg.msg}`; broadcast(message); } /** * 隨機指定長度(len)的字符串 */ function getRndStr(len=1){ var rndStr = ''; for (; rndStr.length < len; rndStr += Math.random().toString(36).substr(2)); return rndStr.substr(0, len); }
客戶端代碼以下:
client:dom
const net = require('net'); const cout = process.stdout; const cin = process.stdin; var client = null; var nick = ''; cout.write(`請輸入暱稱:`); //監聽命令行輸入 cin.on('data',(chunk)=>{ if(chunk.toString()!='\r\n'){ if(client === null){ nick = (chunk+'').replace(/[\r\n]/ig,""); createClient(); }else{ msg = (chunk+'').replace(/[\r\n]/ig,""); client.write(JSON.stringify({ cmd: 'chat', msg: msg, nick: nick })); //若是輸入是exit或quit則斷開鏈接並退出 if(msg.toLowerCase() == 'exit' || msg.toLowerCase() == 'quit'){ client.end(); cin.end(); return; } cout.write(`你說:${msg}\n\r`); } }else{ cout.write(`請輸入暱稱:`); } }); function addListener(client) { client.on('connect', () => { cout.write(`已鏈接到服務器\n\r`); client.write(JSON.stringify({ cmd: 'login', msg: 'hello server', nick: nick })); }); client.on('end', (chunk) => { cout.write(`與服務器斷開鏈接.\n\r`); }); client.on('data', (chunk) => { //若是是心跳信息則迴應keep命令 if(chunk.toString()=='::'){ client.write(JSON.stringify({ cmd: 'keep', msg: '', nick: nick })); return ; } cout.write(`${chunk}\n\r`); }); client.on('error', (err) => { cout.write(`an error has occured.\n\r${err}`); }); } /** * 建立socket並鏈接服務器 */ function createClient(){ console.log('\033[2J');//清屏操做 cout.write(`輸入'EXIT OR QUIT'退出聊天室.\r\n`); client = new net.Socket() client.connect({port:8060/*,host:'1.1.1.69'*/}); addListener(client); }
執行結果以下以下:
socket
到此,一個命令行聊天室便作完了。學習