UDN-企业互联网技术人气社区

板块导航

浏览  : 473
回复  : 3

[Nodejs] 利用Node.js的Net模块实现一个命令行多人聊天室

[复制链接]
genie1003的头像 楼主
发表于 2017-1-2 15:05:58 | 显示全部楼层 |阅读模式
  1、net模块基本API

  要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用。NET模块API分为两大类:Server和Socket类、工厂方法。

  Server类如下图所示:
1.png

  net.Server类可以用来创建一个TCP或本地服务器,继承了EventEmitter。

  Socket类如下:
1.png

  net.Socket类一般用创建一个socket客户端或者是net.Server connection事件的参数。

  工厂方法如下:
1.png

  以上三个图展示了API的使用,其实NET模块的内部原理和C++网络编程差不多的,都是以下步骤。

  服务端:

  • 创建socket套接字
  • 绑定IP和端口
  • 启动监听
  • 等待客户端连接
  • 与客户端进行通信
  • 关闭socket

  客户端:

  • 创建socket套接字
  • 连接server服务器
  • 与服务器进行通信
  • 关闭socket

  如下图所示:
1.jpg

  2、聊天室的设计和实现

  上面学习了NET模块API的使用,接下来便开始实现命令行聊天室,我们不需要做的很复杂,只需实现如下功能即可:

  • 用户自定义昵称,不可更改
  • 当有新的用户进入聊天室,或者用户离开聊天室,广播给其他用户
  • 用户发送信息,需广播给其他用户
  • 客户端与服务端建立心跳机制
  • 用户输入'exit'或者'quit'可以退出聊天室

  确定功能之后,便开始代码的编写。这里我就不一步步分析,直接上代码了,首先是服务端:

  Server:
  1. const net = require('net');
  2. const server = net.createServer();
  3. const clients = {};//保存客户端的连接
  4. var client = null;//当前客户连接
  5. var uid = 0;
  6. server.on('connection',(socket)=>{
  7.     //启动心跳机制
  8.     var isOnline = !0;
  9.     var keepAliveTimer = socket.timer = setInterval(()=>{
  10.         if(!isOnline){
  11.             isOnline = !1;
  12.             client = socket;
  13.             quit(socket.nick);
  14.             return;
  15.         }
  16.         if(socket.writable){
  17.             socket.write('::');
  18.         }else{
  19.             client = socket;
  20.             quit(socket.nick);
  21.         }
  22.     },3000);
  23.     socket.on('end',()=>{
  24.         console.log(`client disconnected.\n\r`);
  25.         socket.destroy();
  26.     });
  27.     socket.on('error',(error)=>{
  28.         console.log(error.message);
  29.     });
  30.     socket.on('data',(chunk)=>{
  31.         client = socket;
  32.         var msg = JSON.parse(chunk.toString());
  33.         if(msg.cmd=='keep'){
  34.             isOnline = !0;
  35.             return;
  36.         }
  37.         dealMsg(msg);
  38.     });
  39. });
  40. server.on('error',(err)=>{
  41.     console.log(err);
  42. });
  43. server.on('listening',()=>{
  44.     console.log(`listening on ${server.address().address}:${server.address().port}\n\r`);
  45. });
  46. server.listen(8060);//启动监听
  47. /**
  48. * 处理用户信息
  49. */
  50. function dealMsg(msg){
  51.     const cmd = msg.cmd;
  52.     const funs = {
  53.         'login':login,
  54.         'chat':chat,
  55.         'quit':quit,
  56.         'exit':quit
  57.     };
  58.     if(typeof funs[cmd] !== 'function') return !1;
  59.     funs[cmd](msg);
  60. }
  61. /**
  62. * 释放连接资源
  63. */
  64. function freeConn(conn){
  65.     conn.end();
  66.     delete clients[conn.uuid];
  67.     conn.timer&&clearInterval(conn.timer);
  68. }
  69. /**
  70. * 用户首次进入聊天室
  71. */
  72. function login(msg){
  73.     var uuid = '';
  74.     uuid = getRndStr(15)+(++uid);//产生用户ID
  75.     client.write(`欢迎你,${msg.nick}:这里总共有${Object.keys(clients).length}个小伙伴在聊天.\r\n`)
  76.     client.nick = msg.nick;
  77.     client.uuid = uuid;
  78.     clients[uuid] = client;
  79.     broadcast(`系统:${msg.nick}进入了聊天室.`);

  80. }
  81. /**
  82. * 广播消息
  83. */
  84. function broadcast(msg){
  85.     Object.keys(clients).forEach((uuid)=>{
  86.         if((clients[uuid]!=client)& clients[uuid].writable){
  87.             clients[uuid].write(msg);
  88.         }
  89.     });
  90. }
  91. /**
  92. * 退出聊天室
  93. */
  94. function quit(nick){
  95.     var message = `小伙伴${nick}退出了聊天室.`;
  96.     broadcast(message);
  97.     freeConn(client);
  98. }

  99. function chat(msg){
  100.     if(msg.msg.toLowerCase()=='quit'||msg.msg.toLowerCase()=='exit'){
  101.         quit(msg.nick);
  102.         return ;
  103.     }
  104.     var message = `${msg.nick}说:${msg.msg}`;
  105.     broadcast(message);
  106. }   
  107. /**
  108. * 随机指定长度(len)的字符串
  109. */
  110. function getRndStr(len=1){
  111.     var rndStr = '';
  112.     for (; rndStr.length < len; rndStr += Math.random().toString(36).substr(2));
  113.     return rndStr.substr(0, len);
  114. }
复制代码

  客户端代码如下:

  client:
  1. const net = require('net');
  2. const cout = process.stdout;
  3. const cin = process.stdin;

  4. var client = null;
  5. var nick = '';

  6. cout.write(`请输入昵称:`);
  7. //监听命令行输入
  8. cin.on('data',(chunk)=>{
  9.     if(chunk.toString()!='\r\n'){
  10.         if(client === null){
  11.             nick = (chunk+'').replace(/[\r\n]/ig,"");
  12.             createClient();
  13.         }else{
  14.             msg = (chunk+'').replace(/[\r\n]/ig,"");
  15.             client.write(JSON.stringify({
  16.                 cmd: 'chat',
  17.                 msg: msg,
  18.                 nick: nick
  19.             }));
  20.             //如果输入是exit或quit则断开连接并退出
  21.             if(msg.toLowerCase() == 'exit' || msg.toLowerCase() == 'quit'){
  22.                 client.end();
  23.                 cin.end();
  24.                 return;
  25.             }
  26.             cout.write(`你说:${msg}\n\r`);
  27.         }
  28.     }else{
  29.         cout.write(`请输入昵称:`);
  30.     }
  31. });

  32. function addListener(client) {
  33.     client.on('connect', () => {
  34.         cout.write(`已连接到服务器\n\r`);
  35.         client.write(JSON.stringify({
  36.             cmd: 'login',
  37.             msg: 'hello server',
  38.             nick: nick
  39.         }));
  40.     });
  41.     client.on('end', (chunk) => {
  42.         cout.write(`与服务器断开连接.\n\r`);
  43.     });
  44.     client.on('data', (chunk) => {
  45.         //如果是心跳信息则回应keep命令
  46.         if(chunk.toString()=='::'){
  47.             client.write(JSON.stringify({
  48.                 cmd: 'keep',
  49.                 msg: '',
  50.                 nick: nick
  51.             }));
  52.             return ;
  53.         }
  54.         cout.write(`${chunk}\n\r`);
  55.     });
  56.     client.on('error', (err) => {
  57.         cout.write(`an error has occured.\n\r${err}`);
  58.     });
  59. }
  60. /**
  61. * 创建socket并连接服务器
  62. */
  63. function createClient(){
  64.     console.log('\033[2J');//清屏操作
  65.     cout.write(`输入'EXIT OR QUIT'退出聊天室.\r\n`);
  66.     client = new net.Socket()
  67.     client.connect({port:8060/*,host:'1.1.1.69'*/});
  68.     addListener(client);
  69. }
复制代码

  执行结果如下如下:
1.jpg

  到此,一个命令行聊天室便做完了。

相关帖子

发表于 2017-1-2 15:06:27 | 显示全部楼层
JavaScript依赖于浏览器本身,与操作环境无关,只要计算机能运行浏览器,并支持JavaScript的浏览器,就可正确执行,从而实现了“编写一次,走遍天下”的梦想。
使用道具 举报

回复

发表于 2017-1-2 15:06:28 | 显示全部楼层
前排支持下
使用道具 举报

回复

发表于 2017-1-2 15:06:29 | 显示全部楼层
我是被标题吸引进来的
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部