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服务器(10):处理上传图片
Dec 18 NodeJs
Nodejs学习笔记之Global Objects全局对象
Jan 13 NodeJs
学习 NodeJS 第八天:Socket 通讯实例
Dec 21 NodeJs
详解nodejs 文本操作模块-fs模块(三)
Dec 22 NodeJs
NodeJs安装npm包一直失败的解决方法
Apr 28 NodeJs
CentOS 安装NodeJS V8.0.0的方法
Jun 15 NodeJs
使用Nodejs连接mongodb数据库的实现代码
Aug 21 NodeJs
使用nodeJs来安装less及编译less文件为css文件的方法
Nov 20 NodeJs
Nodejs 发布自己的npm包并制作成命令行工具的实例讲解
May 15 NodeJs
nodejs 使用http进行post或get请求的实例(携带cookie)
Jan 03 NodeJs
如何让Nodejs支持H5 History模式(connect-history-api-fallback源码分析)
May 30 NodeJs
NodeJS开发人员常见五个错误理解
Oct 14 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
第三节 定义一个类 [3]
2006/10/09 PHP
php+ajax实现无刷新分页的方法
2014/11/04 PHP
CodeIgniter钩子用法实例详解
2016/01/20 PHP
thinkPHP微信分享接口JSSDK用法实例
2017/07/07 PHP
php从数据库读取数据,并以json格式返回数据的方法
2018/08/21 PHP
js实现GridView单选效果自动设置交替行、选中行、鼠标移动行背景色
2010/05/27 Javascript
实现变速回到顶部的JavaScript代码
2011/05/09 Javascript
自动刷新网页,自动刷新当前页面,JS调用
2013/06/24 Javascript
浅析js封装和作用域
2013/07/09 Javascript
JavaScript动态创建div属性和样式示例代码
2013/10/09 Javascript
JS版的date函数(和PHP的date函数一样)
2014/05/12 Javascript
js实现键盘Enter键提交表单的方法
2015/05/27 Javascript
学习Bootstrap组件之下拉菜单
2015/07/28 Javascript
概述BootStrap中role=&quot;form&quot;及role作用角色
2016/12/08 Javascript
Iscrool下拉刷新功能实现方法(推荐)
2017/06/26 Javascript
Angular X中使用ngrx的方法详解(附源码)
2017/07/10 Javascript
微信小程序如何获取用户信息
2018/01/26 Javascript
Spring boot 和Vue开发中CORS跨域问题解决
2018/09/05 Javascript
傻瓜式解读koa中间件处理模块koa-compose的使用
2018/10/30 Javascript
详解VSCode配置启动Vue项目
2019/05/14 Javascript
json 带斜杠时如何解析的实现
2019/08/12 Javascript
vscode自定义vue模板的实现
2021/01/27 Vue.js
[43:24]VG vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
python应用程序在windows下不出现cmd窗口的办法
2014/05/29 Python
Python爬虫之网页图片抓取的方法
2018/07/16 Python
详解python的argpare和click模块小结
2019/03/31 Python
Python二元赋值实用技巧解析
2019/10/25 Python
python实现图片转换成素描和漫画格式
2020/08/19 Python
突袭HTML5之Javascript API扩展4—拖拽(Drag/Drop)概述
2013/01/31 HTML / CSS
英国No.1体育用品零售商:SportsDirect.com
2019/10/16 全球购物
党员大会主持词
2014/04/02 职场文书
幼师辞职信范文大全
2015/05/12 职场文书
亮剑观后感600字
2015/06/05 职场文书
新闻稿件写作技巧
2015/07/18 职场文书
解决ObjectMapper.convertValue() 遇到的一些问题
2021/06/30 Java/Android
Python下载商品数据并连接数据库且保存数据
2022/03/31 Python