Nodejs实现多房间简易聊天室功能

1、前端界面代码

  前端不是重点,够用就行,下面是前端界面,具体代码可到github下载。

2、服务器端搭建

  本服务器需要提供两个功能:http服务和websocket服务,由于node的事件驱动机制,可将两种服务搭建在同一个端口下。

  1、包描述文件:package.json,这里用到了两个依赖项,mime:确定静态文件mime类型,socket.io:搭建websocket服务,然后使用npm install  安装依赖

{
 "name": "chat_room",
 "version": "1.0.0",
 "description": "this is a room where you can chat with your friends",
 "main": "index.js",
 "scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "sfs",
 "license": "ISC",
 "dependencies": {
  "socket.io":"2.0.3",
  "mime":"1.3.6"
 }
}

  2、http服务器

  http服务主要是给web浏览器提供静态文件,既浏览器发来一个请求,服务器返回一个响应。

const
  http=require('http'),
  fs=require('fs'),
  path=require('path'),
  mime=require('mime'),
  chatServer=require('./lib/chat_server');

var cache={};//缓存静态文件内容
//发送错误响应
function send404(response){
  response.writeHead(404,{'Content-Type':'text/plain'});
  response.write('Error 4.4:文件未找到。');
  response.end();
}
//发送文件内容
function sendFile(response,filePath,fileContents){
  response.writeHead(
    200,
    {"content-Type":mime.lookup(path.basename(filePath))}
  );
  response.end(fileContents);
}
//查找文件
function serveStatic(response,cache,absPath){
  if(cache[absPath]){
    sendFile(response,absPath,cache[absPath]);
  }else{
    fs.exists(absPath,function(exists){
      if(exists){
        fs.readFile(absPath,function(err,data){
          if(err){
            send404(response);
          }else{
            cache[absPath]=data;
            sendFile(response,absPath,data);
          }
        });
      }else{
        send404(response);
      }
    });
  }
}
//入口
var server=http.createServer(function(request,response){
  var filePath=false;
  console.log(`new request for ${request.url}`);
  if(request.url==='/'){
    filePath='public/index.html';
  }else{
    filePath='public'+request.url;
  }

  var absPath='./'+filePath;
  serveStatic(response,cache,absPath);
});
server.listen(3000,function(){
  console.log("the server is listening on prot 3000.");
});
chatServer.listen(server); //websocket服务也绑定到该端口上

  3、socket服务

  socket.io提供了开箱既用的虚拟通道,所以不需要任务手动转发消息到已连接的的用户,可以使用 socket.broadcast.to(room).emit('message','hello'); room为某个聊天室id

const
  socketio=require('socket.io');
var io,
  guestNumber=1, //用户编号
  nickNames={},  //socket id对应的nickname
  namesUsed={},  //所有已使用的nickname
  allRooms={},  //聊天室--人数
  currentRoom={}; //sockid--聊天室
module.exports.listen=function(server){
  io=socketio.listen(server);
  io.serveClient('log level',1);
  io.sockets.on('connection',function(socket){
    guestNumber=assignGuestName(socket,guestNumber,nickNames);
    joinRoom(socket,'Lobby');
    handleMessageBroadcasting(socket,nickNames);
    handleNameChangeAttempts(socket,nickNames,namesUsed);
    handleRoomJoining(socket);
    socket.on('rooms',function(){
      socket.emit('rooms',JSON.stringify(allRooms));
    });
    handleClientDisconnection(socket,nickNames,namesUsed);
  });
};
//新socket连入,自动分配一个昵称
function assignGuestName(socket,guesetNumber,nickNames){
  var name='Guest'+guestNumber;
  nickNames[socket.id]=name;
  socket.emit('nameResult',{
    success:true,
    name:name
  });
  namesUsed[name]=1;
  return guestNumber+1;
}
//加入某个聊天室
function joinRoom(socket,room){
  socket.join(room);
  var num=allRooms[room];
  if(num===undefined){
    allRooms[room]=1;
  }else{
    allRooms[room]=num+1;
  }
  currentRoom[socket.id]=room;
  socket.emit('joinResult',{room:room});
  socket.broadcast.to(room).emit('message',{
    text:nickNames[socket.id]+' has join '+room+'.'
  });
  var usersinRoom=io.sockets.adapter.rooms[room];
  if(usersinRoom.length>1){
    var usersInRoomSummary='Users currently in '+room+' : ';
    for(var index in usersinRoom.sockets){
      if(index!=socket.id){
        usersInRoomSummary+=nickNames[index]+',';
      }
    }
    socket.emit('message',{text:usersInRoomSummary});
  }
}
//修改昵称
function handleNameChangeAttempts(socket,nickNames,namesUsed){
  socket.on('nameAttempt',function(name){
    if(name.indexOf('Guest')==0){
      socket.emit('nameResult',{
        success:false,
        message:'Names cannot begin with "Guest".'
      });
    }else{
      if(namesUsed[name]==undefined){
        var previousName=nickNames[socket.id];
        delete namesUsed[previousName];
        namesUsed[name]=1;
        nickNames[socket.id]=name;
        socket.emit('nameResult',{
          success:true,
          name:name
        });
        socket.broadcast.to(currentRoom[socket.id]).emit('message',{
          text:previousName+' is now known as '+name+'.'
        });
      }else{
        socket.emit('nameResult',{
          success:false,
          message:'That name is already in use.'
        });
      }
    }
  });
}
//将某个用户的消息广播到同聊天室下的其他用户
function handleMessageBroadcasting(socket){
  socket.on('message',function(message){
    console.log('message:---'+JSON.stringify(message));
    socket.broadcast.to(message.room).emit('message',{
      text:nickNames[socket.id]+ ': '+message.text
    });
  });
}
//加入/创建某个聊天室
function handleRoomJoining(socket){
  socket.on('join',function(room){
    var temp=currentRoom[socket.id];
    delete currentRoom[socket.id];
    socket.leave(temp);
    var num=--allRooms[temp];
    if(num==0)
      delete allRooms[temp];
    joinRoom(socket,room.newRoom);
  });
}
//socket断线处理
function handleClientDisconnection(socket){
  socket.on('disconnect',function(){
    console.log("xxxx disconnect");
    allRooms[currentRoom[socket.id]]--;
    delete namesUsed[nickNames[socket.id]];
    delete nickNames[socket.id];
    delete currentRoom[socket.id];
  })
}

3、客户端实现socket.io

  1、chat.js处理发送消息,变更房间,聊天命令。

var Chat=function(socket){
  this.socket=socket;//绑定socket
}
//发送消息
Chat.prototype.sendMessage=function(room,text){
  var message={
    room:room,
    text:text
  };
  this.socket.emit('message',message);
};
//变更房间
Chat.prototype.changeRoom=function(room){
  this.socket.emit('join',{
    newRoom:room
  });
};
//处理聊天命令
Chat.prototype.processCommand=function(command){
  var words=command.split(' ');
  var command=words[0].substring(1,words[0].length).toLowerCase();
  var message=false;
  switch(command){
    case 'join':
      words.shift();
      var room=words.join(' ');
      this.changeRoom(room);
      break;
    case 'nick':
      words.shift();
      var name=words.join(' ');
      this.socket.emit('nameAttempt',name);
      break;
    default:
      message='Unrecognized command.';
      break;
  }
  return message;
};

  2、chat_ui.js 处理用户输入,根据输入调用chat.js的不同方法发送消息给服务器

function divEscapedContentElement(message){
  return $('<div></div>').text(message);
}
function divSystemContentElement(message){
  return $('<div></div>').html('<i>'+message+'</i>');
}
function processUserInput(chatApp,socket){
  var message=$('#send-message').val();
  var systemMessage;
  if(message.charAt(0)=='/'){
    systemMessage=chatApp.processCommand(message);
    if(systemMessage){
      $('#messages').append(divSystemContentElement(systemMessage));
    }
  }else{
    chatApp.sendMessage($('#room').text(),message);
    $('#messages').append(divSystemContentElement(message));
    $('#messages').scrollTop($('#messages').prop('scrollHeight'));
  }
  $('#send-message').val('');
}

  3、init.js客户端程序初始化   创建一个websocket连接,绑定事件。

if(window.WebSocket){
  console.log('This browser supports WebSocket');
}else{
  console.log('This browser does not supports WebSocket');
}
var socket=io.connect();
$(document).ready(function(){
  var chatApp=new Chat(socket);
  socket.on('nameResult',function(result){
    var message;
    if(result.success){
      message='You are known as '+result.name+'.';
    }else{
      message=result.message;
    }
    console.log("nameResult:---"+message);
    $('#messages').append(divSystemContentElement(message));
    $('#nickName').text(result.name);
  });
  socket.on('joinResult',function(result){
    console.log('joinResult:---'+result);
    $('#room').text(result.room);
    $('#messages').append(divSystemContentElement('Room changed.'));
  });
  socket.on('message',function(message){
    console.log('message:---'+message);
    var newElement=$('<div></div>').text(message.text);
    $('#messages').append(newElement);
    $('#messages').scrollTop($('#messages').prop('scrollHeight'));
  });
  socket.on('rooms',function(rooms){
    console.log('rooms:---'+rooms);
    rooms=JSON.parse(rooms);
    $('#room-list').empty();
    for(var room in rooms){
      $('#room-list').append(divEscapedContentElement(room+':'+rooms[room]));
    }
    $('#room-list div').click(function(){
      chatApp.processCommand('/join '+$(this).text().split(':')[0]);
      $('#send-message').focus();
    });
  });
  setInterval(function(){
    socket.emit('rooms');
  },1000);
  $('#send-message').focus();
  $('#send-button').click(function(){
    processUserInput(chatApp,socket);
  });
});

完整代码,可到https://github.com/FleyX/ChatRoom 下载。

以上所述是小编给大家介绍的Nodejs实现多房间简易聊天室功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 基于Nodejs利用socket.io实现多人聊天室

    socket.io简介 在Html5中存在着这样的一个新特性,引入了websocket,关于websocket的内部实现原理可以看这篇文章,这篇文章讲述了websocket无到有,根据协议,分析数据帧的头,进行构建websocket.虽然代码短,但可以很好地体现websocket的原理. ,这个特性提供了浏览器端和服务器端的基于TCP连接的双向通道.但是并不是所有的浏览器都支持websocket特性,故为了磨平浏览器间的差异,为开发者提供统一的接口,引入了socket.io模块.在不支持webs

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

    今天我来实现一个简单的聊天室,后台用nodejs, 客户端与服务端通信用socket.io,这是一个比较成熟的websocket框架. 初始工作 1.安装express, 用这个来托管socket.io,以及静态页面,命令npm install express --save,--save可以使包添加到package.json文件里. 2.安装socket.io,命令npm install socket.io --save. 编写服务端代码 首先我们通过express来托管网站,并附加到socke

  • 使用Angular和Nodejs、socket.io搭建聊天室及多人聊天室

    一,利用Node搭建静态服务器 这个是这个项目的底层支撑部分.用来支持静态资源文件像html, css, gif, jpg, png, javascript, json, plain text等等静态资源的访问.这里面是有一个mime类型的文件映射. mime.js /** * mime类型的 map * @ author Cheng Liufeng * @ date 2014/8/30 * 当请求静态服务器文件的类型 html, css, gif, jpg, png, javascript,

  • Nodejs实现多房间简易聊天室功能

    1.前端界面代码 前端不是重点,够用就行,下面是前端界面,具体代码可到github下载. 2.服务器端搭建 本服务器需要提供两个功能:http服务和websocket服务,由于node的事件驱动机制,可将两种服务搭建在同一个端口下. 1.包描述文件:package.json,这里用到了两个依赖项,mime:确定静态文件mime类型,socket.io:搭建websocket服务,然后使用npm install  安装依赖 { "name": "chat_room",

  • nodejs和react实现即时通讯简易聊天室功能

    npx create-react-app socketio-demo 进入socketio-demo目录 运行eject进行拆包,本项目也可以不拆,这是个人习惯. 注意如果运行eject命令最好在项目初始阶段执行,已经开始编写后不要再使用容易出现bug,新人谨慎使用eject命令 yarn eject 项目拆包后创建服务器文件夹和文件 mkdir server type null>index.js 创建完成后目录如下 编写即时通讯(聊天室)后台 安装nodejs插件 npm i express

  • ASP.net(C#)实现简易聊天室功能

    本文实例为大家分享了ASP.net(C#)实现简易聊天室功能的具体代码,供大家参考,具体内容如下 1.搭建框架 <html > <head>     <title>聊天系统</title> </head>     <frameset rows="80%,20%" >           <frameset cols="20%,80%">           <frame src

  • node+socket实现简易聊天室功能

    本文实例为大家分享了node+socket实现简易聊天室的具体代码,供大家参考,具体内容如下 服务端 const net = require('net') const server = net.createServer() //用户列表 let clients = [] //监听连接 server.on('connection',client=>{ client.on('data',(chunk)=>{ let data = chunk.toString() if(data.match(/lo

  • NodeJS实现一个聊天室功能

    看效果 一直说我喜欢卖关子,这次直接看效果: 聊天界面(喜欢的可以自己画一个比较逼真的页面) 前文 先说一下为什么写这个东西,最近不是在写NodeJS知识点的梳理嘛,但是我发现梳理的过程着实无聊的要死,虽然已经快梳理一半了,只是还没发布,这个不重要,重要的是不做点什么东西确实无聊,所以今天把我做这个的过程记录给你们看一下,喜欢的可以拿去玩玩.实现的功能是可以聊天,可以显示用户自定义的昵称,并且显示发送时间 PS:这个功能如果我们使用webstorm新建一个express app的项目的话,是可以

  • golang基于websocket实现的简易聊天室程序

    本文实例讲述了golang基于websocket实现的简易聊天室.分享给大家供大家参考,具体如下: 先说点无关的,最近忙于工作没有更新博客,今天休息顺便把golang websocket研究了一下,挺好玩的,写了一个聊天室,分享给大家. websocket包 : code.google.com/p/go.net/websocket 文档 : http://go.pkgdoc.org/code.google.com/p/go.net/websocket 首先安装websocket包 复制代码 代码

  • Python实现基于C/S架构的聊天室功能详解

    本文实例讲述了Python实现基于C/S架构的聊天室功能.分享给大家供大家参考,具体如下: 一.课程介绍 1.简介 本次项目课是实现简单聊天室程序的服务器端和客户端. 2.知识点 服务器端涉及到asyncore.asynchat和socket这几个模块,客户端用到了telnetlib.wx.time和thread这几个模块. 3.所需环境 本次课中编写客户端需要用到wxPython,它是一个GUI工具包,请先使用下面的命令安装: $ sudo apt-get install python-wxt

  • python实现简易聊天室(Linux终端)

    本文实例为大家分享了python实现简易聊天室的具体代码,供大家参考,具体内容如下 群聊聊天室 1.功能:类似qq群聊功能 1.有人进入聊天室需要输入姓名,姓名不能重复 2.有人进入聊天室,其他人会受到通知 xxx进入聊天室 3.一个人发消息,其他人会受到消息 xxx:xxxxxxxx 4.有人退出聊天室,其他人也会收到通知 xxx退出聊天室 5.扩展功能:服务端消息公告,服务端发送消息所有人都能收到 管理员消息:xxxxxxxx 2.确定技术模型 1.服务端和客户端 服务端处理请求,发送管理员

  • Linux下Select多路复用实现简易聊天室示例

    目录 前言 多路复用的原理 基本概念 select fd_set 服务器Code 客户端Code 效果演示 select服务器 客户端Ⅰ 客户端Ⅱ 前言 和之前的udp聊天室有异曲同工之处,这次我们客户端send的是一个封装好了的数据包,recv的是一个字符串,服务器recv的是一个数据包,send的是一个字符串,在用户连接的时候发送一个login请求,然后服务器端处理,并广播到其他客户端去 多路复用的原理 基本概念 多路复用指的是:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读

随机推荐