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的前后端分离的思考与实践(二)模版探索
Sep 26 NodeJs
Nodejs中调用系统命令、Shell脚本和Python脚本的方法和实例
Jan 01 NodeJs
nodejs简单实现中英文翻译
May 04 NodeJs
iPhone手机上搭建nodejs服务器步骤方法
Jul 06 NodeJs
Nodejs读取文件时相对路径的正确写法(使用fs模块)
Apr 27 NodeJs
nodejs socket实现的服务端和客户端功能示例
Jun 02 NodeJs
nodejs之get/post请求的几种方式小结
Jul 26 NodeJs
nodejs简单读写excel内容的方法示例
Mar 16 NodeJs
Nodejs实现的操作MongoDB数据库功能完整示例
Feb 02 NodeJs
Nodejs对postgresql基本操作的封装方法
Feb 20 NodeJs
nodejs同步调用获取mysql数据时遇到的大坑
Mar 02 NodeJs
浅谈Node的内存泄露问题
May 06 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将时间差转换为字符串提示
2011/09/07 PHP
php单例模式实现(对象只被创建一次)
2012/12/05 PHP
php带抄送和密件抄送的邮件发送方法
2015/03/20 PHP
php+ajax无刷新上传图片实例代码
2015/11/17 PHP
php中bind_param()函数用法分析
2017/03/28 PHP
PHP实现广度优先搜索算法(BFS,Broad First Search)详解
2017/09/16 PHP
PHP等比例压缩图片的实例代码
2018/07/26 PHP
利用PHP计算有多少小于当前数字的数字方法示例
2020/08/26 PHP
提高网站性能之 如何对待JavaScript
2009/10/31 Javascript
Javascript匿名函数的一种应用 代码封装
2010/06/27 Javascript
浅谈javascript的数据类型检测
2010/07/10 Javascript
Dojo 学习要点
2010/09/03 Javascript
使用javascript创建快捷方式的简单实例
2013/08/09 Javascript
jquery实现点击变换导航样式的方法
2015/08/31 Javascript
JS原型链怎么理解
2016/06/27 Javascript
jquery实现ajax加载超时提示的方法
2016/07/23 Javascript
AngularJS 视图详解及示例代码
2016/08/17 Javascript
对称加密与非对称加密优缺点详解
2017/02/06 Javascript
Vue.js中组件中的slot实例详解
2017/07/17 Javascript
JS排序算法之冒泡排序,选择排序与插入排序实例分析
2017/12/13 Javascript
傻瓜式解读koa中间件处理模块koa-compose的使用
2018/10/30 Javascript
ES6 新增的创建数组的方法(小结)
2019/08/01 Javascript
解决vue一个页面中复用同一个echarts组件的问题
2020/07/19 Javascript
[01:05:40]VG vs Newbee 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
python实现爬虫统计学校BBS男女比例之数据处理(三)
2015/12/31 Python
Python3之读取连接过的网络并定位的方法
2018/04/22 Python
python2与python3中关于对NaN类型数据的判断和转换方法
2018/10/30 Python
Python装饰器语法糖
2019/01/02 Python
python/Matplotlib绘制复变函数图像教程
2019/11/21 Python
后端开发使用pycharm的技巧(推荐)
2020/03/27 Python
澳大利亚百货公司:David Jones
2018/02/08 全球购物
优秀女职工事迹材料
2014/02/06 职场文书
颐和园英文导游词
2015/01/30 职场文书
降价通知函
2015/04/23 职场文书
2016年优秀班主任先进事迹材料
2016/02/26 职场文书
关于党风廉政建设宣传教育月的活动总结!
2019/08/08 职场文书