bob体育官方平台
传说socket.io+express的闲聊室demo,令你快速上手socket.io

vue + vuex + elementUi + socket.io实现一个简易的在线聊天室,提高自己在对vue系列在项目中应用的深度。因为学会一个库或者框架容易,但要结合项目使用一个库或框架就不是那么容易了。功能虽然不多,但还是有收获。设计和实现思路较为拙劣,恳请各位道友指正。

基于socket.io+express的聊天室demo

可以达到的需求

一,案例的效果图

图片 1

image

1,刚刷新时出新用户名输入的input框,用于输入用户的用户信息

图片 2

image

2,用户上线后,浏览器上线时的提示

图片 3

image

3,聊天室群发消息

图片 4

image

4,聊天室单发消息

图片 5

image

5,聊天室发送图片

具体大家可以去我的coding克隆这个项目:socket.io+express聊天室demo

能查看在线用户列表 能发送和接受消息

二,聊天室框架搭建

1,因为案例是基于express的demo,可以使用官网的express应用生成器生成应用。

npm install express-generator -g 

2,在相应目录下生成文件

express myapp

3,进入这个应用,并安装相应依赖

cd myapp 
npm install

4,紧接着运行程序

npm start  // 或者 node ./bin/www 

5,相应的目录结构如下

.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── css
│   ├── images
│   ├── javascripts
│   ├── js
│   ├── stylesheets
│   └── stylesheets
│       ├── main.css
│       ├── style.css
│       ├── ...
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.jade
    ├── index.jade
    └── layout.jade

使用到的框架和库

三,聊天时的消息提示类

使用了插件Sco.js和bootstrap的HubSpot 弹框组件库,具体的使用这里不过多的介绍,大家可以看看官方的api或者适应你自己的消息提示插件。

socket.io做为实时通讯基础 vuex/vue:客户端Ui层使用 Element-ui:客户端Ui组件

四,socket.io的介绍

1,什么是socket.io

由于http是无状态的协议,所以实现聊天等通信功能非常困难,当别人发送一条消息时,服务器并不知道当前有哪些用户等着收消息,所以以前实现聊天通信功能最普遍的就是轮询机制了,客户端定期发一个请求,看看有没有人发送消息到服务器上了,如果有,服务器就将消息发给该客户端。

缺点显而易见,那么多的请求消耗了大量资源,有大量的请求其实是浪费了。

现在,我们有了WebSocket,他是HTML5的新api。 WebSocket 连接本质上就是一个 TCP 连接,WebSocket会通过http请求建立,建立后的WebSocket会在客户端和服务器端建立一个持久的连接,直到有一方主动的关闭了该连接。所以现在服务器就知道有哪些用户正在连接了,这样通讯就变得相对容易了

Socket.io实际上是WebSocket的父集,Socket.io封装了WebSocket和轮询等方法,他会根据情况选择方法来进行通讯。

2,在express整合socket.io

  • 首先,在根目录新建serverchat.js
var io = require('socket.io')();

exports.listen = function(_server){
    io.listen(_server);
};
  • 接着在bin目录下的www文件的require(http)后引入serverchat.js
var io = require('../serverchat');
  • 同时将io挂到我们的server下,并注释掉我们之前开启服务的server.listen(port);
io.listen(server); 

server.listen(port); //将这段删除或者注释

这里还有一个需要注意的是,我们不能使用var server = http.createServer(app);这段代码创建一个服务了,而是需要用以下代码创建服务,否则服务启动不了。

var server = app.listen(app.get('port'), function() {
  debug('node_chat server listening on port ' + server.address().port);
});

类文件关系图

五,socket.io的连接,断开。

1,在服务器端

serverchat.js中,我们处理相关的关于socket.io的代码

io.on('connection',function(socket){
  socket.on('disconnect',function(){
    });
}) // 使用这段代码进行socket的连接

这里我们要注意的是接下去我们要做的关于信息发送等操作,都是要在连接的前提下建立的,只有当我们连接了socket之后,我们才能做我们想让socket为我们做的事情。

2,在客户端中

我们在public/javascript下建立两个文件,chat.jsclient.js

chat.js中我们主要做的事接受服务端请求,并通过client.js中的关于jq的处理页面相关的方法。

这里我们大可以把所有的js写在一个文件中,但是我们分成两个写的话,会是代码更佳移动,好维护。

3,接下来在index.jade中引入这两个js

script(src='/javascripts/chat.js')
script(src='/javascripts/client.js')

这里说到的关于jade的语法,大家如果还不是特别熟的话,可以去参考jade官网,里面有详细的介绍。

服务端实现

六,用户登录

这里的登录是假登录,我们只是需要获取用户input框里面输入的姓名以及用户的头像图片。

1,客户端

当用户在输入框中输入名字,确定之后,客户端会发一个信息给服务端,socket通过emit这个函数发送信息,通过on这个函数接受信息。

client.js

// 用户登录
    $('#btn-setName').click(function(){
        var name = $('#username').val();
        console.log(name);

        if(checkUser(name)){
            $('#username').val('');
            alert('Nickname already exists or can not be empty!');
        } else {
            // 随机头像
            var imgList = [".jpg",".jpg",".jpg",".jpg",".jpg"];
            var randomNum = Math.floor(Math.random()*5);

            var img = imgList[randomNum];

            // 发送到服务端的用户信息数据
            var dataObj = {
                name:name,
                img:img
            };

            socket.emit('login',dataObj);
            // 隐藏modal

            $('#myModal').modal('hide');
            $('#username').val('');
            $('#msg').focus();
        }
    })

2,服务端

得到客户端传过来的数据,将用户信息塞入到服务端的userList,服务器将新的userList发送给各个客户端。

var userList = [];

socket.on('login', function(user){
    user.id = socket.id;
    userList.push(user);

    io.emit('userList',userList); // 发送给所有的用户
    socket.emit('userInfo',user); // 发送给自己
    socket.broadcast.emit('loginInfo',user.name+"上线了。"); 
    //发送给出自己外的用户
});

3,客户端

chat.js中接收userList,客户端接受到新的userList的时候,渲染新的用户聊天室列表,在接受到新的userInfo的时候在列表左侧显示相应的“欢迎你,用户名”字样。

// 用户列表渲染
socket.on('userList',function(userlist){
    addUser(userlist);
})
// 用户信息渲染
socket.on('userInfo',function(userObj){
    //should be use cookie or session
    userSelf = userObj; // 真实的登录应该把用户信息存在session里。
  $('#spanuser').text('欢迎您! '+userObj.name);
})

至此,我们便完成一个简单的socket的数据的交互。

实现聊天服务器的相关功能,包含通讯管道的创建、用户加入、消息的接受与转发等。

七,发送单聊与群聊

  • 群聊,比较简单,我们可以通过socket广播socket.broadcast.emit(),发送给除自己以外的用户。
socket.on('toAll',function(msgObj){
    socket.broadcast.emit('toAll',msgObj); 
});
  • 单聊,刚刚我们讲过socket.emit()是发送信息给自己,每一个socket有自己的id,我们只需要将socket的id变成我们要发送的那个用户的id,我们就能实现单聊了。
socket.on('toOne',function(msgObj){
    var toSocket = _.findWhere(io.sockets.sockets,{id:msgObj.to});
    toSocket.emit('toOne', msgObj);
})

上面的 - 是我们引用的 underscore ,处理数据的一个库。具体可以查看underscore中文文档,通过npm install underscore --save安装依赖。同时我们可以通过 io.sockets.sockets 获取所有的socketid

一、通讯服务建立

八,如何发送图片

我们可以通过h5的api——FileReader(),这个api会将图片转化为base64格式的,然后就可以进行发送了,

1,客户端

//send image to all
  $('#sendImage').change(function(){
    if(this.files.length != 0){
        var file = this.files[0];
        reader = new FileReader();
        if(!reader){
            alert("!your browser doesn't support fileReader");
            return;
        }
        reader.onload = function(e){   // 加载文件
            var msgObj = {
                from:userSelf,
                img:e.target.result
            };
            socket.emit('sendImageToALL',msgObj); 
            addImgFromUser(msgObj,true);
        };
        reader.readAsDataURL(file);  // 将图片转化为base64格式的
    }
  });

2,服务端

将信息发送给客户端,客户端转发给除了自己的其他socket用户

//sendImageToALL
socket.on('sendImageToALL',function(msgObj){
    socket.broadcast.emit('sendImageToALL',msgObj);
})

3,客户端

chat.js中接受相应的图片socket信息,

socket.on('sendImageToALL',function(msgObj){
  addImgFromUser(msgObj,false);
});

client.js 中,将图片进行相应的dom操作,将图片渲染进去。 base64 格式的也可以通过 <img src="" /> 标签中的src进行渲染。

build/server-config.js:聊天服务器的入口

九,对于文章的一些说明

1,此篇文章的demo是我在学习一个socket.io视频时的demo做的,非常感谢这个老师的视频。

2,我写这篇文章的目的是希望能给没有时间去看视频学习,同时又懒得去看文档的小伙伴们一个快速了解 socket.io 制作聊天室。

3,如需要这个视频的小伙伴,可以在私信我向我要。

4,文章可能会存在很多问题,欢迎小伙伴批评指正哦

let socketIo = require;let express = require; let cxt = require('../src/services-server');let httpPort = 9001;let channelId = 1let app = express();app.get{ res.send;}); let server = require.createServer;let io = socketIo;io.on('connection',function{ console.log; cxt.createChannel;server.listen; //用server连接console.log('io listen success !! ' + httpPort);

通过express创建一个server对象,然后利用socketIo创建io对象 然后通过io的on方法监听connection事件 当有客户端连接时,触发connection事件,县立即调用"服务端上下文"的createChannel方法创建一个管道,此时的管道上是没有用户信息的。

二、创建上下文

实现一个聊天室上下文,包含:用户、房间、消息、管道等数组,所以代码都在service-server目录中。

index.js:聊天室服务端上下文创建入口,创建context,并初始化房间到上下文中。 context.js:聊天室服务端上下文类,用户、房间、消息、管道等类在此中做集中管理。 room目录:包含房间和房间集合的实现 channel:服务端与客户端通讯的管道类

结合"通讯服务建立"中的connectiong事件的触,其后转到cxt.createChannel方法

createChannel  { let channel = new Channel channel.init() channel.index = this.channels.length this.channels.push}

此时会创建一个管道实例,然后初始化管道实例,并将管道添加到管道数组中。以下是初始化管道实例的代码:

init () { let self = this let roomInfo = this.cxt.room.collections[0] this.roomInfo = roomInfo this.socket.join('roomId' + roomInfo.id) this.socket.emit(this.cxt.eventKeys.emit.sendRooms, roomInfo) /* send出去一个默认的房间 */ this.socket.on(this.cxt.eventKeys.client.registerUser, function  { console.log(id + '-' + name + '--' + self.id) self.cxt.createUserById /** 新用户注册 */ this.socket.on(this.cxt.eventKeys.client.newMsg, function  { /** 发送消息 */ self.notifyMsg self.cxt.addMsg this.socket.on(this.cxt.eventKeys.client.closeConn, function () { console.log self.cxt.remove this.sendUsers()}

在初始化管道实例时做了如下事件:

返回顶部