十三、利用socket.io实现简单聊天室

实现服务端代码

首先安装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
    
    
        


完成页面效果
image.png

你可能感兴趣的:(十三、利用socket.io实现简单聊天室)