实现服务端代码
首先安装socket.io
npm install socket.io
let http = require('http');
let https = require('https');
let fs = require('fs');
let express = require('express');
let serveIndex = require('serve-index');
let socketIo = require('socket.io')
let log4js = require('log4js')
log4js.configure({
appenders: {
file: {
type: 'file',
filename: 'app.log',
layout: {
type: 'pattern',
pattern: '%r %p - %m'
}
}
},
categories: {
default: {
appenders: ['file'],
level: 'debug'
}
}
})
let logger = log4js.getLogger()
let app = express();
app.use(serveIndex('./public'));
app.use(express.static('./public'));
// http server
let http_server = http.createServer(app);
// https server
let options = {
key: fs.readFileSync('./msxf.dev.key'),
cert: fs.readFileSync('./msxf.dev.crt')
}
let https_server = https.createServer(options, app);
// 将https服务和socket.io绑定 443为复用端口,既可以响应web服务,又可以响应socket.io服务
let io = socketIo.listen(https_server)
let sockio = socketIo.listen(http_server);
io.sockets.on('connection', (socket) => {
socket.on('message', (room, data) => {
socket.to(room).emit('message', room, data) // 房间内所有人,除自己外
})
// 改函数应该加锁
// "join" 是自定义 action
socket.on('join', (room) => {
socket.join(room) // socket.join 是socket提供的join方法,可以加入房间,如果是第一个用户,则新建房间并加入
let myRoom = io.sockets.adapter.rooms[room] // 拿到房间对象
let users = Object.keys(myRoom.sockets).length
logger.log(`the number if user in room is: ${users}`)
/**
* 在这里可以控制进入房间的人数,现在一个房间最多 2个人
* 为了便于客户端控制,如果是多人的话,应该将目前房间里
* 人的个数当做数据下发下去
*/
if(users < 3) {
socket.emit('joined', room, socket.id) // 给本人回消息
if (users > 1) {
socket.to(room).emit('joined', room, socket.id) // 给房间内除了自己外所有人回消息
}
}else {
socket.leave(room)
socket.emit('full', room, socket.id)
}
// io.in(room).emit('joined', room, socket.id) // 给房间内所有人回消息
// socket.broadcast.emit('joined', room, socket.id) // 除自己,全部站点
})
socket.on('leave', (room) => {
let myRoom = io.sockets.adapter.rooms[room] // 拿到房间对象
let users = Object.keys(myRoom.sockets).length
// users - 1
logger.log(`the number if user in room is: ${users - 1}`)
socket.leave(room) // socket.leave 是socket提供的leave方法
socket.to(room).emit('leaved', room, socket.id) // 给房间内除了自己外所有人回消息
socket.emit('leaved', room, socket.id) // 给本人回消息
// io.in(room).emit('leaved', room, socket.id) // 给房间内所有人回消息
// socket.broadcast.emit('leaved', room, socket.id) // 除自己,全部站点
})
})
//connection
sockio.sockets.on('connection', (socket)=>{
socket.on('message', (room, data)=>{
sockio.in(room).emit('message', room, socket.id, data)//房间内所有人
});
socket.on('join', (room)=> {
socket.join(room);
var myRoom = sockio.sockets.adapter.rooms[room];
var users = Object.keys(myRoom.sockets).length;
logger.log('the number of user in room is: ' + users);
socket.emit('joined', room, socket.id);
//socket.to(room).emit('joined', room, socket.id);//除自己之外
//io.in(room).emit('joined', room, socket.id)//房间内所有人
//socket.broadcast.emit('joined', room, socket.id);//除自己,全部站点
});
socket.on('leave', (room)=> {
var myRoom = sockio.sockets.adapter.rooms[room];
var users = Object.keys(myRoom.sockets).length;
//users - 1;
logger.log('the number of user in room is: ' + (users-1));
socket.leave(room);
socket.emit('leaved', room, socket.id);
//socket.to(room).emit('joined', room, socket.id);//除自己之外
//io.in(room).emit('joined', room, socket.id)//房间内所有人
//socket.broadcast.emit('joined', room, socket.id);//除自己,全部站点
});
});
http_server.listen(811, '127.0.0.1');
https_server.listen(443, '127.0.0.1')
注:使用https://127.0.0.1:443打开页面,请求 socket.io 会出现400 bad request
使用http://127.0.0.1:811可以正常使用
老师的课程中未出现此问题,猜想https需要域名访问,不可以用IP吧
实现客户端代码
let userName = document.querySelector('input#username')
let inputRoom = document.querySelector('input#room')
let btnConnect = document.querySelector('button#connect')
let btnLeave = document.querySelector('button#leave')
let outputArea = document.querySelector('textarea#output')
let inputArea = document.querySelector('textarea#input')
let btnSend = document.querySelector('button#send')
let socket
let room
btnConnect.onclick = () => {
// connect
socket = io.connect()
// recieve message
// 加入房间后 处理逻辑
socket.on('joined', (room, id) => {
btnConnect.disabled = true
inputRoom.disabled = true
btnLeave.disabled = false
inputArea.disabled = false
btnSend.disabled = false
})
// 离开房间后 处理逻辑
socket.on('leaved', (room, id) => {
btnConnect.disabled = false
inputRoom.disabled = false
btnLeave.disabled = true
inputArea.disabled = true
btnSend.disabled = true
})
// 收到消息后 处理逻辑
socket.on('message', (room, id, data) => {
outputArea.scrollTop = outputArea.scrollHeight;//窗口总是显示最后的内容
outputArea.value = `${outputArea.value}/${data}\r`
})
// 离开房间
socket.on('disconnect', (socket) => {
btnConnect.disabled = false
inputRoom.disabled = false
btnLeave.disabled = true
inputArea.disabled = true
btnSend.disabled = true
})
// send message
room = inputRoom.value
socket.emit('join', room)
}
btnSend.onclick = () => {
let data = inputArea.value
data = `${userName.value}:${data}`
socket.emit('message', room, data)
inputArea.value = ''
}
btnLeave.onclick = () => {
room = inputRoom.value
socket.emit('leave', room)
}
inputArea.onkeypress = (event) => {
if(event.keyCode == 13) {
let data = inputArea.value
data = `${userName.value}:${data}`
socket.emit('message', room, data)
inputArea.value = ''
event.preventDefault() // 阻止默认行为
}
}
Chat Room