Principle and function summary of node chat room and socket.io

Time:2021-7-16

IntroductionA few days ago, I made a simple chat room, which realized the chat function. The chat content can send text, pictures, audio, video, expression pack and other content, supporting one-to-one chat and group chat. Now on the previous chat room function to do a simple comb and summary.

catalogue

  • Brief introduction of principle
  • Function development
  • Effect experience

Brief introduction of principle

This time it was usedsocket.ioThis toolkit communicates.

webscoket

HTML5 has the function of websocket. Please refer to this article “websocket of HTML knowledge summary” for more basic knowledge.

Websocket is a full duplex communication protocol on a single TCP connection, which can save server resources and bandwidth, and communicate in real time.

Extracurricular Science Popularization:

Communication is divided into parallel communication, serial communication, synchronous / asynchronous, simplex / duplex, half duplex / full duplex.

  • Parallel communicationIt means that each data member sends or receives data on multiple data lines at the same time. The control is simple and the transmission speed is fast; Because there are many transmission lines, it is suitable for short distance communication.
  • serial communicationIt means that the data is sent and received bit by bit on the same data line. The control is complex and the transmission speed is slow; It only needs one data line and is suitable for long distance communication.

    • According to the demarcation, timing and synchronization scheme of data stream, it can be divided into synchronous serial communication and asynchronous communication.
    • According to the direction of serial data transmission, we can divide the communication into simplex, half duplex and duplex.

      • Simplex: refers to the data transmission can only be along one direction, can not achieve reverse transmission.
      • Half duplex: refers to the data transmission can be along two directions, but need time-sharing transmission.
      • Full duplex: data can be transmitted in two directions at the same time.

socket.io

socket.ioIt is a mature solution based on websocket protocol. The advantages are good performance and multi platform support; The disadvantage is that the transmitted data does not completely follow the websocket protocol, which requires that both the client and the server must use the socket.io solution.

difference

  • Both HTTP and websocket are based on TCP;
  • HTTP establishes a short connection;
  • Websocket establishes a long connection;

Function development

Now we will analyze this function and develop the front-end and back-end content. Let’s get through the back-end part to prepare for the front-end connection to socket service.

The following shows the most basic chat room, including the following functions:

  • Multi person chat
  • Display user name and number of people
  • Carriage return
  • To the top

Back end

Here is how to set up Socket server in node.

Install dependency package

npm install -g express-generator
express --view=ejs chat
cd chat
npm install
npm install socket.io

Configure socket.io

openbin/wwwFile, invar server = http.createServer(app);The next line writes the following.

The following content separately introduces each content, does not do the entire code paste.

  • Introduce WS service
const ws = require('socket.io');
const io = ws(server, {
  path: '/chat',
  transports: [
    'polling',
    'websocket'
  ]
})

common method

  • Connecting and disconnecting
io.on('connection', socket => {

    console.log('a user connected!');

    //disconnect
    socket.on('disconnect', () => {
        console.log('a user disconnected!');
    })
}
  • Join and leave the room
// join room
socket.join(roomId);

// leave room
socket.leave(roomId);
  • Accept the message
socket.on('event name', data => {
    // data
}
  • send message
socket.emit('event name', {
    // some data
});
  • Broadcast to others
socket.broadcast.emit('event name', {
    // some data
});
  • Send a message to a room
io.to(roomId).emit('event name', {
    // some data
})

summary procedure

let roomInfo = {};

io.on('connection', socket => {
  let roomId = socket.handshake.query.roomId;

  // user login
  socket.on('login', data => {
    
    socket.join(roomId);

    if (!(roomId in roomInfo)) {
      roomInfo[roomId] = [];
    }

    let names = [];
    let users = roomInfo[roomId];
    if (users.length) {
      for (let i = 0; i < users.length; i++) {
        names.push(users[i].name);
      }
      if (!(names.includes(data.user))) {
        users.push({
          id: socket.id,
          name: data.name,
          avatar: data.avatar
        })
      }
    } else {
      roomInfo[roomId].push({
        id: socket.id,
        name: data.name,
        avatar: data.avatar
      });
    }

    console.log('roomInfo: ', roomInfo);

    io.to(roomId).emit('system', {
      name: data.name,
      users: roomInfo[roomId]
    })

  })

  // client msg
  socket.on('message', data => {
    io.to(roomId).emit('chat', data);
  })

  // leave room
  socket.on('leave', data => {
    let users = roomInfo[roomId];
    if (users && users.length) {
      for (let i = 0; i < users.length; i++) {
        const user = users[i];
        if (data.name == user.name) {
          users.splice(i, 1);
        }
        
      }
    }

    socket.leave(roomId);

    io.to(roomId).emit('logout', {
      name: data.name,
      users: roomInfo[roomId]
    })

    console.log('roomInfo: ', roomInfo);

  })

  socket.on('disconnect', () => {
    console.log('a user disconnect!');
  })

});

Front end

  • introducesocket.io.jsfile
<script></script>
  • HTML section

Login interface:

<div class="chat">
  <h2>XQ chat room</h2>
  <form class="chat-form">
      <p>
          < label for = "name" > nickname: < / label >
          < input type = text "id = name" name = name "placeholder = please enter user name" required >
      </p>
      <p>
          < label for = "Avatar" > Avatar: < / label >
          <select name="avatar" id="avatar" required>
              < option value = "avatar1" > avatar 1 < / option >
              < option value = "avatar2" > Avatar 2 < / option >
              < option value = "avatar3" > avatar 3 < / option >
          </select>
      </p>
      <p>
          < label for = "roomid" > Room: < / label >
          <select name="roomId" id="roomId" required>
              < option value = "1" > Room 1 < / option >
              < option value = "2" > Room 2 < / option >
              < option value = "3" > Room 3 < / option >
          </select>
      </p>
      <p>
          < input type = "submit" value = "enter room" >
      </p>
  </form>
</div>

Room interface:

<div class="room">
    <div class="room-header">
        <h3>XQ chat room (< span class = "count" > 0 < / span >)</h3>
        < button class = "logout" > Exit < / button >
    </div>
    <div class="room-nav">
        < small > number of people online: < / small >
        < span id = "room users" > no members</span>
    </div>
    <ul class="room-content">
    </ul>
    <div class="room-footer">
        < input class = room IPT "type = text" placeholder = feel free to write ">
        < input class = room BTN "type = submit" value = send ">
    </div>
</div>
  • CSS part
body {
    margin: 0;
    padding: 0;
    background: #f9f9f9;
}

h1,h2,h3,h4,h5,h6,p {
    margin: 0;
}

ul,li {
    margin: 0;
    padding: 0;
    list-style: none;
}

.chat {
    box-sizing: border-box;
    margin: 50px auto;
    padding: 20px;
    width: 300px;
    height: auto;
    background: #fff;
}

.chat.active {
    display: none;
}

.chat h2 {
    margin-bottom: 10px;
    font-size: 18px;
    line-height: 1.5;
    text-align: center;
}

.chat-form p {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 5px 0;
    font-size: 15px;
    line-height: 35px;
}

.chat-form p label {
    width: 50px;
}

.chat-form p input,
.chat-form p select {
    flex: 1;
    box-sizing: border-box;
    padding: 0 10px;
    height: 30px;
    border: 1px solid #ccc;
    outline: none;
    background: none;
}

.chat-form p input:focus,
.chat-form p select:focus {
    box-shadow: 0 0 5px #ccc;
}

.room {
    display: none;
    width: 100%;
    height: 100vh;
    overflow: hidden;
}

.room.active {
    display: flex;
    flex-direction: column;
}

.room-header {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: center;
    box-sizing: border-box;
    padding: 0 15px;
    height: 60px;
    background: #111;
    color: #fff;
}

.room-header h3 {
    font-size: 18px;
    text-align: left;
}

.room-header button {
    width: 50px;
    height: 50px;
    background: none;
    color: #fff;
    outline: none;
    border: none;
    text-align: right;
}

.room-nav {
    box-sizing: border-box;
    padding: 20px 15px;
    line-height: 30px;
    font-size: 14px;
}

.room-nav small,
.room-nav span {
    font-size: 14px;
}

.room-nav span {
    color: rgb(6, 90, 146);
}

.room-content {
    flex: 1;
    padding: 15px 0;
    background: #fff;
    border-top: 1px solid #ccc;
    border-bottom: 1px solid #ccc;
    background: #eee;
    overflow-x: hidden;
    overflow-y: auto;
}

.room-content li {
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;
    box-sizing: border-box;
    padding: 15px 10px;
    margin-bottom: 10px;
    width: 100%;
}

.room-content li .room-user {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.room-content li img {
    display: inline-block;
    width: 40px;
    height: 40px;
}

.room-content li span {
    font-size: 14px;
}

.room-des {
    position: relative;
    margin-top: 5px;
    margin-left: 10px;
    box-sizing: border-box;
    padding: 3px 5px;
    font-size: 14px;
    line-height: 30px;
    background: #ccc;
    border-radius: 5px;
}

.room-des::before,
.room-des::after {
    content: '';
    position: absolute;
    top: 10px;
    width: 0;
    height: 0;
    border: 5px solid transparent;
}

.room-des::before {
    display: inline-block;
    left: -10px;
    border-right: 5px solid #ccc;
}

.room-des::after {
    display: none;
    right: -10px;
    border-left: 5px solid #fff;
}

.room-me {
    flex-direction: row-reverse;
}

.room-me .room-des {
    margin-left: 0;
    margin-right: 10px;
    background: #fff;
}

.room-me .room-des::before {
    display: none;
}

.room-me .room-des::after {
    display: inline-block;
}

.room-content .system {
    justify-content: center;
    align-items: center;
    padding: 0;
    height: 35px;
    line-height: 35px;
}

.system p {
    box-sizing: border-box;
    padding: 0 5px;
    font-size: 14px;
    text-align: center;
    border-radius: 5px;
    background: #ccc;
}

.room-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 50px;
    background: #fff;
    border-top: 1px solid #ccc;
}

.room-footer .room-ipt {
    margin-top: 1px;
    box-sizing: border-box;
    padding: 10px;
    width: 80%;
    height: 48px;
    background: none;
    border: 1px solid transparent;
    outline: none;
}

.room-footer .room-ipt:focus {
    border: 1px solid #ccc;
    box-shadow: 0 0 5px #ccc;
}

.room-footer .room-btn {
    width: 19%;
    height: 100%;
    background: rgb(2, 54, 112);
    border: 1px solid #ccc;
    outline: none;
    font-size: 15px;
    color: #fff;
}
  • JS part

JS of login interface

let chat = document.querySelector('.chat');
let chatForm = document.querySelector('.chat-form');
let user = document.querySelector('#name');
let avatar = document.querySelector('#avatar');
let roomId = document.querySelector('#roomId');

// io
let socket = io.connect('/', {
    path: '/chat'
});

// login
chatForm.onsubmit = function(){
    let userInfo = {
        name: user.value,
        avatar: `/img/${avatar.value}.webp`,
        roomId: roomId.value
    }
    localStorage.setItem('userInfo', JSON.stringify(userInfo));
    checkLogin();
    return false;
};

checkLogin();

function checkLogin () {

    let userInfo = localStorage.getItem('userInfo');
    userInfo = JSON.parse(userInfo);

    if (userInfo && userInfo.name) {
        chat.classList.add('active');
        room.classList.add('active');
        socket.emit('login', userInfo);

    } else {
        chat.classList.remove('active');
        room.classList.remove('active');
    }

}

JS of room part

let room = document.querySelector('.room');
let logout = document.querySelector('.logout');
let count = document.querySelector('.count');
let roomUsers = document.querySelector('#room-users');
let roomContent = document.querySelector('.room-content');
let roomIpt = document.querySelector('.room-ipt');
let roomBtn = document.querySelector('.room-btn');

//Log out
logout.addEventListener('click', function(){
    let userInfo = localStorage.getItem('userInfo');
    userInfo = JSON.parse(userInfo);
    socket.emit('leave', userInfo);
    Alert ('Quit successfully ');
    localStorage.removeItem('userInfo');
    checkLogin();
})

roomIpt.addEventListener('keyup', sendMsg, false);
roomBtn.addEventListener('click', sendMsg, false);

//Send message 
function sendMsg (e) {
    if (e.type === 'click' || e.code === 'Enter') {
        let val = roomIpt.value;
        if (val == '') {
            Alert ('chat content cannot be empty ');
            return false;
        }
        let userInfo = localStorage.getItem('userInfo');
        userInfo = JSON.parse(userInfo);
        userInfo.msg = val;
        roomIpt.value = '';
        socket.emit('message', userInfo);
        goBot();
    }
}

goBot();

//To the bottom
function goBot () {
    roomContent.scrollTop = roomContent.scrollHeight;
}

//System message prompt
function welcome (user = 'mark', type = 1) {
    roomContent.innerHTML += `
        <li class="system">
            <p>System message: < strong > ${user} < / strong > ${type = = 1? " Come to ':'leave'} This room</ p>
        </li>
    `;
    goBot();
}

//System message
socket.on('system', data => {
    let strs = '';
    welcome(data.name);
    count.innerText = data.users.length;
    for (const item of data.users) {
        strs += item.name + ',';
    }
    roomUsers.innerText = '';
    roomUsers.innerText += strs;
})


//Exit reminder
socket.on('logout', data => {
    let strs = '';
    welcome(data.name, 2);
    count.innerText = data.users.length;
    for (const item of data.users) {
        strs += item.name + ',';
    }
    roomUsers.innerText = '';
    roomUsers.innerText += strs;
})

//Accept the message
socket.on('chat', data => {
    let userInfo = localStorage.getItem('userInfo');
    userInfo = JSON.parse(userInfo);
    let isUser = data.name == userInfo.name;
    roomContent.innerHTML += `
        <li ${isUser ? 'class="room-me"' : ''}>
            <div class="room-user">
                <img class="room-avatar">
                <span class="room-name">${isUser ? userInfo.name : data.name }</span>
            </div>
            <p class="room-des">${data.msg}</p>
        </li>
    `;
    goBot();
})

Effect experience

Finally, let’s experience the wonderful life of XQ chat room!

  • get into the room

First of all, enter your own nickname, select your avatar and room, and click the enter room button to talk.
Principle and function summary of node chat room and socket.io

  • send message

Then, enter the message content and click the send button, or pressEnterReturn is OK.
Principle and function summary of node chat room and socket.io

You can open a privacy traceless window or a new browser, open the web address, and enter another test account

This is Jerry’s interface after logging in
Principle and function summary of node chat room and socket.io

This is the message mark saw from Jerry
Principle and function summary of node chat room and socket.io

  • Log out

If the chat is over, you can click on the top right to exit the chat room.
Principle and function summary of node chat room and socket.io

This is the interface mark sees after Jerry logs out
Principle and function summary of node chat room and socket.io

Let’s take a look at the user information printed on the back end.

  • This is the information mark recorded after logging in
    Principle and function summary of node chat room and socket.io
  • This is what Jerry recorded after logging in
    Principle and function summary of node chat room and socket.io
  • This is what Jerry recorded after he quit
    Principle and function summary of node chat room and socket.io

The above is a simple chat room and nodewebsocketSummary of knowledge.

Recommended Today

Lua language novice simple tutorial

1、 Foreword Lua is a lightweight and compact scripting language, which is written in standard C language and open in the form of source code. Its design purpose is to be embedded in the application, so as to provide flexible expansion and customization functions for the application. Lua can be applied in game development, independent […]