nodejs socket.io

1,635 阅读3分钟

1.首先我们看下效果图

附上github地址,github.com/windlany/ha…

运行node server.js,打开localhost:3000



2.目录结构


服务端代码

项目用到的技术主要是nodejs+express,socket.io,fileReader,

server.js:服务端代码

chat-client.js:客户端代码

3.搭建服务器

搭建服务器有两种方式,

(1)通过nodejs

var http = require('http');

http.createServer(function (request, response) {
    // 发送 HTTP 头部 
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead(200, {'Content-Type': 'text/plain'});
    // 发送响应数据 "Hello World"
    response.end('Hello World\n');
}).listen(8888);

// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');

(2)nodejs+express

var express = require('express');
var app = express();
var http = require('http').Server(app);
// 路由为/默认www静态文件夹
app.use('/', express.static(__dirname + '/www'));
http.listen(3000, function() {    
console.log('listen 3000 port.');
});
express.static是express提供的内置中间件,用来设置静态文件目录,可以直接访问图片等静态资源http://localhost:3000/image/bg3.jpg

4.客户端和服务端建立连接

和服务器建立连接需要用到实时通信工具socket.io,通过npm等包管理工具安装,

服务端通过connection监听客户端的连接

io.on('connection', (socket)=> {
   //
})

客户端通过socket.io模块的实例化对象io建立与服务端的连接

 var socket = io(); 

socket.io的语法前后端通用,通过socket.emit() 触发事件,通过socket.on() 来监听和处理事件,通过传递的参数进行通信。每个客户端有专门的socket。

io.emit(foo); //会触发所有用户的foo事件   
socket.emit(foo); //只触发当前用户的foo事件   
socket.broadcast.emit(foo); //触发除了当前用户的其他用户的foo事件

5.登录

client:

输入姓名登录,触发服务端的login事件,并注册了登录成功loginSuc和登录失败loginError两个事件

   $('#nameBtn').click(inputName);    
    socket.on('loginSuc', ()=> {       
$('.name').hide();     
})    socket.on('loginError', ()=> {      
alert('用户名已存在,请重新输入!');      
$('#name').val('');    });   
   socket.on('system', (user)=> {       
var data = new Date().toTimeString().substr(0, 8);      
$('#messages').append(`<p class='system'><span>${data}</span><br /><span>${user.name}  
${user.status}了聊天室<span></p>`);      
// 滚动条总是在最底部      
$('#messages').scrollTop($('#messages')[0].scrollHeight);   
 });   
socket.on('disUser', (usersInfo)=> {      
displayUser(usersInfo);   
});
function inputName() {      
var imgN = Math.floor(Math.random()*4)+1; // 随机分配头像      
if($('#name').val().trim()!=='')          
socket.emit('login', {             
name: $('#name').val(),            
img: 'image/user' + imgN + '.jpg'          
});  // 触发登录事件      
return false;     
}
function displayUser(users) {      
$('#users').text(''); 
// 每次都要重新渲染      
if(!users.length) {        
$('.contacts p').show();      
} else {        
$('.contacts p').hide();     
 }      
$('#num').text(users.length);      
for(var i = 0; i < users.length; i++) {        
var $html = `<li>          
<img src="${users[i].img}">          
<span>${users[i].name}</span>        
</li>`;        
$('#users').append($html);      
}    

server:

服务端监听到login事件,

(1)判断当前用户名是否注册过,注册过,触发客户端的loginError事件,

未注册过,触发客户端的loginSuc,system,disUser事件,向所有客户端广播xxx进入聊天室,

右侧在线人员展示等

socket.on('login', (user)=> {        
if(users.indexOf(user.name) > -1) {             
socket.emit('loginError');       
 } else {            
users.push(user.name);            
usersInfo.push(user);
            socket.emit('loginSuc');            
socket.nickname = user.name;           
 io.emit('system', {               
name: user.name,                
status: '进入'           
 });           
 io.emit('disUser', usersInfo);            
console.log(users.length + ' user connect.');       
 }    
});

6.发送消息

client:

客户端发送消息,触发服务端的sendMsg事件

$('#sub').click(sendMsg);var color = '#000000';     function sendMsg() {       if($('#m').val() == '') {        alert('请输入内容!');        return false;      }      color = $('#color').val();       socket.emit('sendMsg', {        msg: $('#m').val(),        color: color,        type: 'text'      });      $('#m').val('');       return false;     }
 socket.on('receiveMsg', (obj)=> {       
// 发送为图片      
if(obj.type == 'img') {        
$('#messages').append(`          
<li class='${obj.side}'>            
<img src="${obj.img}">            
<div>              
<span>${obj.name}</span>              
<p style="padding: 0;">${obj.msg}</p>           
 </div>          
</li>       
 `);        
 $('#messages').scrollTop($('#messages')[0].scrollHeight);        
return;      
}
      // 提取文字中的表情加以渲染      
var msg = obj.msg;      
var content = '';      
while(msg.indexOf('[') > -1) { 
 // 其实更建议用正则将[]中的内容提取出来       
 var start = msg.indexOf('[');        
var end = msg.indexOf(']');
        content += '<span>'+msg.substr(0, start)+'</span>';       
 content += '<img src="image/emoji/emoji%20('+msg.substr(start+6, end-start-6)+').png">';     
   msg = msg.substr(end+1, msg.length);      }      content += '<span>'+msg+'</span>';          
  $('#messages').append(`        <li class='${obj.side}'>          <img src="${obj.img}">     
    <div>            <span>${obj.name}</span>            <p style="color: ${obj.color};">${content}</p>  
        </div>        </li>      `);      // 滚动条总是在最底部     
 $('#messages').scrollTop($('#messages')[0].scrollHeight);   
 }); 

server:

服务端监听到sendMsg事件,触发客户端的receiveMsg事件,当前客户端消息显示在右侧,其他客户端显示在左侧

  socket.on('sendMsg', (data)=> {     
   var img = '';       
 for(var i = 0; i < usersInfo.length; i++) {      
      if(usersInfo[i].name == socket.nickname) {    
            img = usersInfo[i].img;        
    }     
   }       
 socket.broadcast.emit('receiveMsg', {       
     name: socket.nickname,         
   img: img,          
  msg: data.msg,   
         color: data.color,        
    type: data.type,          
  side: 'left'      
  });  
      socket.emit('receiveMsg', {        
    name: socket.nickname,      
      img: img,        
    msg: data.msg,      
      color: data.color,    
        type: data.type,        
    side: 'right'       
 });  
  });  

7.发送图片

client:

使用FileReader对象,web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可以使用File对象来指定所要处理的文件或数据。

FileReader通过异步的方式读取文件内容,结果均是通过事件回调获取

$('#file').change(function() {      
var file = this.files[0];  // 上传单张图片      
var reader = new FileReader();
      //文件读取出错的时候触发      
reader.onerror = function(){          
console.log('读取文件失败,请重试!');       
};      
// 读取成功后      
reader.onload = function() {        
var src = reader.result;  // 读取结果        
var img = '<img class="sendImg" src="'+src+'">';        
socket.emit('sendMsg', {  // 发送          
msg: img,          
color: color,          
type: 'img'        
});      
 };      
reader.readAsDataURL(file); // 读取为64位
    });