nodejs实现的一个简单聊天室功能分享


Posted in NodeJs onDecember 06, 2014

今天我来实现一个简单的聊天室,后台用nodejs, 客户端与服务端通信用socket.io,这是一个比较成熟的websocket框架.

初始工作

1.安装express, 用这个来托管socket.io,以及静态页面,命令npm install express --save,--save可以使包添加到package.json文件里.
2.安装socket.io,命令npm install socket.io --save.

编写服务端代码

首先我们通过express来托管网站,并附加到socket.io实例里,因为socket.io初次连接需要http协议

var express = require('express'),

    io = require('socket.io');
var app = express();
app.use(express.static(__dirname));
var server = app.listen(8888);


var ws = io.listen(server);

添加服务器连接事件,当客户端连接成功之后,发公告告诉所有在线用户,并且,当用户发送消息时,发广播通知其它用户.
ws.on('connection', function(client){

    console.log('\033[96msomeone is connect\033[39m \n');

    client.on('join', function(msg){

        // 检查是否有重复

        if(checkNickname(msg)){

            client.emit('nickname', '昵称有重复!');

        }else{

            client.nickname = msg;

            ws.sockets.emit('announcement', '系统', msg + ' 加入了聊天室!');

        }

    });

    // 监听发送消息

    client.on('send.message', function(msg){

        client.broadcast.emit('send.message',client.nickname,  msg);

    });

    // 断开连接时,通知其它用户

    client.on('disconnect', function(){

        if(client.nickname){

            client.broadcast.emit('send.message','系统',  client.nickname + '离开聊天室!');

        }

    })
})

由于客户端是通过昵称来标识的,所以服务端需要一个检测昵称重复的函数

// 检查昵称是否重复

var checkNickname = function(name){

    for(var k in ws.sockets.sockets){

        if(ws.sockets.sockets.hasOwnProperty(k)){

            if(ws.sockets.sockets[k] && ws.sockets.sockets[k].nickname == name){

                return true;

            }

        }

    }

    return false;

}

编写客服端代码

由于服务端采用第三方websokcet框架,所以前端页面需要单独引用socket.io客户端代码,源文件可以从socket.io模块里找,windows下路径为node_modules\socket.io\node_modules\socket.io-client\dist,这里有开发版和压缩版的,默认引用开发版就行.

前端主要处理输入昵称检查,消息处理,完整代码如下:

<!DOCTYPE html>

<html>

<head>

    <title>socket.io 聊天室例子</title>

    <meta charset="utf-8">

    <link rel="stylesheet" href="css/reset.css"/>

    <link rel="stylesheet" href="css/bootstrap.css"/>

    <link rel="stylesheet" href="css/app.css"/>

</head>

<body>

    <div class="wrapper">

         <div class="content" id="chat">

             <ul id="chat_conatiner">

             </ul>

         </div>

         <div class="action">

             <textarea ></textarea>

             <button class="btn btn-success" id="clear">清屏</button>

             <button class="btn btn-success" id="send">发送</button>

         </div>

    </div>

    <script type="text/javascript" src="js/socket.io.js"></script>

    <script type="text/javascript">
          var ws = io.connect('http://172.16.2.184:8888');

          var sendMsg = function(msg){

              ws.emit('send.message', msg);

          }

          var addMessage = function(from, msg){

              var li = document.createElement('li');

              li.innerHTML = '<span>' + from + '</span>' + ' : ' + msg;

              document.querySelector('#chat_conatiner').appendChild(li);
              // 设置内容区的滚动条到底部

              document.querySelector('#chat').scrollTop = document.querySelector('#chat').scrollHeight;
              // 并设置焦点

              document.querySelector('textarea').focus();
          }
          var send = function(){

              var ele_msg = document.querySelector('textarea');

              var msg = ele_msg.value.replace('\r\n', '').trim();

              console.log(msg);

              if(!msg) return;

              sendMsg(msg);

              // 添加消息到自己的内容区

              addMessage('你', msg);

              ele_msg.value = '';

          }
          ws.on('connect', function(){

              var nickname = window.prompt('输入你的昵称!');

              while(!nickname){

                  nickname = window.prompt('昵称不能为空,请重新输入!')

              }

              ws.emit('join', nickname);

          });
          // 昵称有重复

          ws.on('nickname', function(){

              var nickname = window.prompt('昵称有重复,请重新输入!');

              while(!nickname){

                  nickname = window.prompt('昵称不能为空,请重新输入!')

              }

              ws.emit('join', nickname);

          });
          ws.on('send.message', function(from, msg){

              addMessage(from, msg);

          });
          ws.on('announcement', function(from, msg){

              addMessage(from, msg);

          });
          document.querySelector('textarea').addEventListener('keypress', function(event){

              if(event.which == 13){

                  send();

              }

          });

          document.querySelector('textarea').addEventListener('keydown', function(event){

              if(event.which == 13){

                  send();

              }

          });

          document.querySelector('#send').addEventListener('click', function(){

              send();

          });
          document.querySelector('#clear').addEventListener('click', function(){

              document.querySelector('#chat_conatiner').innerHTML = '';

          });

    </script>

</body>

</html>

这里提供完整的代码压缩文件

总结

nodejs是一个好东西,尤其是在处理消息通讯,网络编程方面,天生的异步IO.

NodeJs 相关文章推荐
nodejs win7下安装方法
May 24 NodeJs
Nodejs实现多人同时在线移动鼠标的小游戏分享
Dec 06 NodeJs
详解nodejs 文本操作模块-fs模块(二)
Dec 22 NodeJs
详解redis在nodejs中的应用
May 02 NodeJs
Nodejs异步回调之异常处理实例分析
Jun 22 NodeJs
nodejs 如何手动实现服务器
Aug 20 NodeJs
nodejs遍历文件夹下并操作HTML/CSS/JS/PNG/JPG的方法
Nov 01 NodeJs
NodeJs实现简单的爬虫功能案例分析
Dec 05 NodeJs
nodejs图片处理工具gm用法小结
Dec 12 NodeJs
纯异步nodejs文件夹(目录)复制功能
Sep 03 NodeJs
nodeJS与MySQL实现分页数据以及倒序数据
Jun 05 NodeJs
nodejs+koa2 实现模仿springMVC框架
Oct 21 NodeJs
详谈nodejs异步编程
Dec 04 #NodeJs
nodejs下打包模块archiver详解
Dec 03 #NodeJs
nodejs中转换URL字符串与查询字符串详解
Nov 26 #NodeJs
nodejs教程之制作一个简单的文章发布系统
Nov 21 #NodeJs
nodejs教程之环境安装及运行
Nov 21 #NodeJs
nodejs教程之异步I/O
Nov 21 #NodeJs
nodejs教程之入门
Nov 21 #NodeJs
You might like
php whois查询API制作方法
2011/06/23 PHP
php数组函数序列之prev() - 移动数组内部指针到上一个元素的位置,并返回该元素值
2011/10/31 PHP
PHP常用特殊运算符号和函数总结(php新手入门必看)
2013/02/02 PHP
php匹配字符中链接地址的方法
2014/12/22 PHP
Yii2中使用join、joinwith多表关联查询
2016/06/30 PHP
javascript的原生方法获取数组中的最大(最小)值
2012/12/19 Javascript
Javascript selection的兼容性写法介绍
2013/12/20 Javascript
Node.js实现的简易网页抓取功能示例
2014/12/05 Javascript
JS实现具备延时功能的滑动门菜单效果
2015/09/17 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之绑定事件
2015/11/19 Javascript
以JavaScript来实现WordPress中的二级导航菜单的方法
2015/12/14 Javascript
浅析函数声明和函数表达式——函数声明的声明提前
2016/05/03 Javascript
利用node.js爬取指定排名网站的JS引用库详解
2017/07/25 Javascript
jQuery实现鼠标响应式淘宝动画效果示例
2018/02/13 jQuery
详解如何使用koa实现socket.io官网的例子
2018/11/04 Javascript
详解JS实现系统登录页的登录和验证
2019/04/29 Javascript
ES6 Object属性新的写法实例小结
2019/06/25 Javascript
vant-ui组件调用Dialog弹窗异步关闭操作
2020/11/04 Javascript
Vue 数据响应式相关总结
2021/01/28 Vue.js
[02:50]2014DOTA2 TI预选赛预选赛 大神专访第一弹!
2014/05/21 DOTA
[05:09]第二届DOTA2亚洲邀请赛决赛日比赛集锦:iG 3:0 OG夺冠
2017/04/05 DOTA
简单的通用表达式求10乘阶示例
2014/03/03 Python
Python脚本实现格式化css文件
2015/04/08 Python
python实现逆波兰计算表达式实例详解
2015/05/06 Python
一个基于flask的web应用诞生 使用模板引擎和表单插件(2)
2017/04/11 Python
使用Python3内置文档高效学习以及官方中文文档
2019/05/19 Python
python针对mysql数据库的连接、查询、更新、删除操作示例
2019/09/11 Python
win10下python2和python3共存问题解决方法
2019/12/23 Python
让IE支持HTML5的方法
2012/12/11 HTML / CSS
Html5基于canvas实现电子签名并生成PDF文档
2020/12/07 HTML / CSS
奥地利顶级内衣丝袜品牌英国站:Wolford英国
2016/08/29 全球购物
美国领先的机场停车聚合商:Airport Parking Reservations
2020/02/28 全球购物
车间副主任岗位职责
2013/12/24 职场文书
2014银行领导班子四风对照检查材料思想汇报
2014/09/25 职场文书
新生入学欢迎词
2015/01/26 职场文书
公司表扬稿范文
2015/05/05 职场文书