前言 可以毫不夸张的说,Node.js的出现带动了整个前端界的繁荣发展,自此进入百花齐放,百家争鸣的时代。时至今天,我们能用Node.js实现很多依靠传统服务器端编程语言才能实现的事,甚至更加简便、更加高效。 本案例使用Node.js的net模块,建立服务端与客户端的Socket连接,简单实现了客户端广播消息通信和点对点通信。
项目结构 server.js 服务端 项目下的server.js是服务端的执行文件,用于创建服务端的Socket服务,监听指定端口;接收客户端传过来的数据,解析数据并按照数据中附带的协议进行广播消息通信或点对点通信。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 const net = require ('net' );let clients = {};let server = net.createServer ((socket ) => { function signin (clientDataContent ) { clientDataContent = JSON .parse (clientDataContent); let username = clientDataContent.from ; if (Object .keys (clients).length ) { let onlineNotice = { protocol : 'online' , online : username, onlineCount : Object .keys (clients).length + 1 }; for (let username in clients) { if (clients.hasOwnProperty (username)) { let noticeClient = clients[username]; noticeClient.write (JSON .stringify (onlineNotice)); } } } clients[username] = socket; console .log (`欢迎 ${socket.remoteAddress} :${socket.remotePort} 【${username} 】,加入聊天室,当前在线:${Object .keys(clients).length} ` ); } function broadcast (clientDataContent ) { let sendClientData = JSON .parse (clientDataContent); for (let username in clients) { if (clients.hasOwnProperty (username)) { let client = clients[username]; client.write (JSON .stringify (sendClientData)); } } } function p2p (clientDataContent ) { let p2pClientData = JSON .parse (clientDataContent); clients[p2pClientData.to ].write (JSON .stringify (p2pClientData)); } socket.on ('data' , (chunk ) => { try { let clientDataContent = chunk.toString ().trim (); let protocol = JSON .parse (clientDataContent).protocol ; switch (protocol) { case 'signin' : signin (clientDataContent); break ; case 'broadcast' : broadcast (clientDataContent); break ; case 'p2p' : p2p (clientDataContent); break ; default : socket.write ('错误!未能识别的通信协议!' ); break ; } } catch (error) { socket.write ('出现错误了哦~' ); throw error; } }); socket.on ('error' , (error ) => { let deletekey = null ; for (let username in clients) { if (clients.hasOwnProperty (username)) { let client = clients[username]; if (socket === client) deletekey = username; } } delete clients[deletekey]; let offlineNotice = { protocol : 'offline' , offline : deletekey, onlineCount : Object .keys (clients).length }; for (let username in clients) { if (clients.hasOwnProperty (username)) { let noticeClient = clients[username]; noticeClient.write (JSON .stringify (offlineNotice)); } } console .log (`${deletekey} 下线了,当前在线:${Object .keys(clients).length} ` ); }); }); let port = 2018 ;server.listen (port, (error ) => { if (error) { console .log (`${port} 端口被占用!` ); } else { console .log (`服务器端正常启动,正在监听${port} 端口` ); } });
client.js 客户端 项目下的client.js是客户端的执行文件,用于创建客户端的Socket服务。将用户输入的内容按特定的格式组成数据结构发给服务端,同时打印出服务端指定的内容。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 const net = require ('net' );const readline = require ('readline' );const rl = readline.createInterface (process.stdin , process.stdout );rl.question ('请输入聊天昵称:' , (nickname ) => { nickname = nickname.trim (); if (!nickname) { throw new Error ('昵称不能为空!' ); } let server = net.connect ({port : 2018 , host : '127.0.0.1' }, () => { let user = { protocol : 'signin' , from : nickname }; server.write (JSON .stringify (user)); console .log (`【系统通知】已成功加入聊天室,尽情畅聊吧~` ); server.on ('data' , (chunk ) => { try { let serverDataContent = JSON .parse (chunk.toString ().trim ()); let protocol = serverDataContent.protocol ; switch (protocol) { case 'online' : console .log (`\n【系统通知】欢迎:${serverDataContent.online} ,加入聊天室,当前在线人数:${serverDataContent.onlineCount} \n` ); rl.prompt (); break ; case 'offline' : console .log (`\n【系统通知】${serverDataContent.offline} 下线了,当前在线人数:${serverDataContent.onlineCount} \n` ); rl.prompt (); break ; case 'broadcast' : console .log (`\n[@所有人] ${serverDataContent.from } > ${serverDataContent.message} \n` ); rl.prompt (); break ; case 'p2p' : console .log (`\n[@${serverDataContent.to} ] ${serverDataContent.from } > ${serverDataContent.message} \n` ); rl.prompt (); break ; default : server.write ('错误!未能识别的通信协议!' ); break ; } } catch (error) { server.write ('出现错误了哦~' ); throw error; } }); rl.setPrompt (nickname + '> ' ); rl.prompt (); rl.on ('line' , (line ) => { line = line.toString ().trim (); let arrString = line.split (':' ); let sendServerData = null ; if (arrString.length === 2 ) { sendServerData = { protocol : 'p2p' , from : nickname, to : arrString[0 ], message : arrString[1 ] }; } else { sendServerData = { protocol : 'broadcast' , from : nickname, message : line }; } server.write (JSON .stringify (sendServerData)); rl.prompt (); }); rl.on ('close' , () => { }); }); });
实现功能 目前已实现:客户端广播消息通信、点对点通信。
项目使用
启动服务端,$ node server.js
启动第一个客户端,$ node client.js
启动第二个客户端,$ node client.js
……
演示视频
项目下载 本案例源代码托管于GitHub,下载:传送门