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服务器(10):处理上传图片
Dec 18 NodeJs
使用DNode实现php和nodejs之间通信的简单实例
Jul 06 NodeJs
用nodeJS搭建本地文件服务器的几种方法小结
Mar 16 NodeJs
nodejs入门教程二:创建一个简单应用示例
Apr 24 NodeJs
Nodejs中使用captchapng模块生成图片验证码
May 18 NodeJs
nodejs socket服务端和客户端简单通信功能
Sep 14 NodeJs
使用npm安装最新版本nodejs
Jan 18 NodeJs
nodejs 简单实现动态html的方法
May 12 NodeJs
对mac下nodejs 更新到最新版本的最新方法(推荐)
May 17 NodeJs
Nodejs调用Dll模块的方法
Sep 17 NodeJs
nodejs基础之常用工具模块util用法分析
Dec 26 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
使用数据库保存session的方法
2006/10/09 PHP
php初学者写及时补给skype用户充话费的小程序
2008/11/02 PHP
使用Linux五年积累的一些经验技巧
2013/06/20 PHP
PHP使用SOAP调用API操作示例
2018/12/25 PHP
javascript 单例/单体模式(Singleton)
2011/04/07 Javascript
jquery全选checkBox功能实现代码(取消全选功能)
2013/12/10 Javascript
js控制容器隐藏出现防止样式变化的两种方法
2014/04/25 Javascript
javascript获取和判断浏览器窗口、屏幕、网页的高度、宽度等
2014/05/08 Javascript
自动完成的搜索框javascript实现
2016/02/26 Javascript
JS双击变input框批量修改内容
2016/12/12 Javascript
js遍历json对象所有key及根据动态key获取值的方法(必看)
2017/03/09 Javascript
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
详解a++和++a的区别
2017/08/30 Javascript
bing Map 在vue项目中的使用详解
2018/04/09 Javascript
Redux实现组合计数器的示例代码
2018/07/04 Javascript
详解多页应用 Webpack4 配置优化与踩坑记录
2018/10/16 Javascript
微信小程序在地图选择地址并返回经纬度简单示例
2018/12/03 Javascript
Vue 设置axios请求格式为form-data的操作步骤
2019/10/29 Javascript
webpack安装配置与常见使用过程详解(结合vue)
2020/06/01 Javascript
[03:37]2014DOTA2国际邀请赛 主赛事第一日胜者组TOPPLAY
2014/07/19 DOTA
[42:23]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第二场 12.10
2020/12/13 DOTA
Python表示矩阵的方法分析
2017/05/26 Python
Pandas 对Dataframe结构排序的实现方法
2018/04/10 Python
浅谈python中拼接路径os.path.join斜杠的问题
2018/10/23 Python
用Python逐行分析文件方法
2019/01/28 Python
python笔记之mean()函数实现求取均值的功能代码
2019/07/05 Python
python生成任意频率正弦波方式
2020/02/25 Python
anaconda3安装及jupyter环境配置全教程
2020/08/24 Python
python实现感知机模型的示例
2020/09/30 Python
Rodd & Gunn澳大利亚官网:新西兰男装品牌
2018/09/25 全球购物
应届生新闻编辑求职信
2013/11/19 职场文书
民族团结演讲稿范文
2014/08/27 职场文书
关于工作经历的证明书
2014/10/11 职场文书
残联2016年全国助残日活动总结
2016/04/01 职场文书
MySQL系列之三 基础篇
2021/07/02 MySQL
MySQL 逻辑备份 into outfile
2022/05/15 MySQL