Websocket + NodeJS implements chat rooms
A, websocket
1. Websocket Introduction
The traditional HTTP protocol, is based on request and response, can not directly do the client to send messages to the client. Websocket protocol is a new network protocol based on TCP. The full-duplex communication between browser and server is realized. Full-duplex: The client can proactively send messages to the server, and the server can also proactively send messages to the client. Websocket is a persistent protocol, and HTTP is a non-persistent traditional HTTP protocol. Even if the chat is implemented, it must be done through Ajax polling, which means that the client will keep sending requests to the server to confirm whether there is a message, wasting performance and resources.
2. Use WebSocket
2.1 Using WebSocket in H5
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div {
width: 200px;
height: 200px;
border: 1px solid # 000;
}
</style>
</head>
<body>
<input type="text" placeholder="Please enter">
<button>send</button>
<! -- Display content -->
<div></div>
<! H5 provides the WebSocket API in the browser -->
<script>
let input = document.querySelector('input');
let button = document.querySelector('button');
let div = document.querySelector('div');
// Create WebSocket('WebSocket server address ')
let socket = new WebSocket('ws://echo.websocket.org');
// Listen for WebSocket event open and WebSocket server connection triggered successfully
socket.addEventListener('open',()=>{
div.innerHTML = 'Connection successful';
});
// Send a message to webSocket
button.addEventListener('click', () = > {let value = input.value;
socket.send(value);
});
// Accept webSocket service messages
socket.addEventListener('message',(msg)=>{
console.log(msg.data);
// Display the message to div
div.innerHTML = msg.data;
});
// Port service
socket.addEventListener('close', () = > {console.log('Service disconnected');
});
</script>
</body>
</html>
Copy the code
Develop WebSocket using NodeJS
Developing WebSocket with NodeJS requires a dependency package nodeJS Webs
npm i nodejs-websocket
App. Js code
const ws = require('nodejs-websocket');
const PORT = 3000
// Create a server. Every time a user connects, the callback execution creates a connect object for the user
const server = ws.createServer(connect= > {
console.log('User connection successful');
// The user sends data, triggering the text event
connect.on('text', data => {
console.log('Received user data:${data}`);
// After receiving the data, give the user the response data
connect.sendText(data);
});
// The close event is triggered when the connection is closed
connect.on('close', () = > {console.log('Disconnected');
});
// Register an error event to trigger the exception after the user port is registered
connect.on('error', () = > {console.log('User connection abnormal');
});
});
server.listen(PORT, () => {
console.log('listen to 3000');
});
Copy the code
Change HTML webSocket server address to ‘ws://localhost:3000/’
Running effect
3. Develop a simple chat room using WebSocket
app.js
const ws = require('nodejs-websocket');
// Record the number of connected users
let count = 0;
const server = ws.createServer(conn= > {
console.log('New connection');
count++;
// Give the user a fixed name
conn.userName = ` user${count}`;
// Tell all users that someone has joined the chat room
broadcast(`${conn.userName}Join a chat room);
// This event is triggered by receiving data from the client
conn.on('text', data => {
// Receive a user's data, tell all users this message, broadcast
broadcast(data);
});
// Close the connection
conn.on('close', () = > {console.log('Close the connection')
count--;
// Let all users know if someone quit
broadcast(`${conn.userName}Left the chat room)});// Send exception
conn.on('error', () = > {console.log('abnormal');
});
});
/ / radio
const broadcast = (msg) = > {
// Server. Connection indicates all users
server.connections.forEach(item= > {
// Iterate over each user and send messages one by one
item.send(msg);
});
}
server.listen(3000, () = > {console.log('listen to 3000');
});
Copy the code
index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
/*div { width: 200px; height: 200px; border: 1px solid #000; } * /
</style>
</head>
<body>
<input type="text" placeholder="Please enter">
<button>send</button>
<! -- Display content -->
<div></div>
<! H5 provides the WebSocket API in the browser -->
<script>
let input = document.querySelector('input');
let button = document.querySelector('button');
let div = document.querySelector('div');
// Create WebSocket('WebSocket server address ')
let socket = new WebSocket('ws://localhost:3000/');
// Listen for WebSocket event open and WebSocket server connection triggered successfully
socket.addEventListener('open',()=>{
div.innerHTML = 'Connection successful';
});
// Send a message to webSocket
button.addEventListener('click', () = > {let value = input.value;
socket.send(value);
input.value = ' ';
});
// Accept webSocket service messages
socket.addEventListener('message',(msg)=>{
console.log(msg.data);
// Append the message to the div
let dv = document.createElement('div');
dv.innerHTML = msg.data;
div.appendChild(dv);
});
// Port service
socket.addEventListener('close', () = > {console.log('Service disconnected');
});
</script>
</body>
</html>
Copy the code
Running effect
3.1. Optimize the effect of chat room messages
To optimize the message as an object:
- Type: indicates the type of the message
- 0: indicates messages that enter the chat room
- 1: indicates a message leaving the chat room
- 2: Normal chat
- MSG: indicates the content of the message
- Time: The specific time of the chat
- Note: Convert this object to JSON format before sending it
app.js
const ws = require('nodejs-websocket');
// Enter the message
const TYPE_ENTER = 0;
// Leave the message
const TYPE_LEAVE = 1;
// Normal message
const TYPE_MSG = 2;
// Record the number of connected users
let count = 0;
const server = ws.createServer(conn= > {
console.log('New connection');
count++;
// Give the user a fixed name
conn.userName = ` user${count}`;
// Tell all users that someone has joined the chat room
broadcast({
type: TYPE_ENTER,
msg: `${conn.userName}Join a chat room.time: new Date().toLocaleDateString()
});
// This event is triggered by receiving data from the client
conn.on('text', data => {
// Receive a user's data, tell all users this message, broadcast
broadcast({
type: TYPE_MSG,
msg: data,
time: new Date().toLocaleDateString()
});
});
// Close the connection
conn.on('close', () = > {console.log('Close the connection')
count--;
// Let all users know if someone quit
broadcast({
type: TYPE_LEAVE,
msg: `${conn.userName}Left the chat room.time: new Date().toLocaleDateString()
})
});
// Send exception
conn.on('error', () = > {console.log('abnormal');
});
});
/ / radio
const broadcast = (msg) = > {
// Server. Connection indicates all users
server.connections.forEach(item= > {
// Iterate over each user and send messages one by one
item.send(JSON.stringify(msg));
});
}
server.listen(3000, () = > {console.log('listen to 3000');
});
Copy the code
The change of the HTML
const TYPE_ENTER = 0;
const TYPE_LEAVE = 1;
const TYPE_MSG = 2;
// Accept webSocket service messages
socket.addEventListener('message',(e)=>{
let data = JSON.parse(e.data);
// Append the message to the div
let dv = document.createElement('div');
// Add effects for different message types
dv.innerHTML = data.msg + The '-' + data.time;
if (data.type === TYPE_ENTER) {
dv.style.color = 'green';
} else if (data.type === TYPE_LEAVE){
dv.style.color = 'red';
} else {
dv.style.color = 'blue';
}
div.appendChild(dv);
});
Copy the code
Running effect
2. Basic usage of socketio
2.1. No frame
Socket.IO is a library for real-time, bidirectional, and event-based communication between browsers and servers. Socket.IO is not an implementation of WebSocket. Install socketio
npm i –save socket.io
app.js
// Create the server
const http = require('http');
const fs = require('fs');
const app = http.createServer();
// Listen for the request event and return index.html when the service is requested
app.on('request', (req, res) => {
fs.readFile(__dirname + '/index.html',
(err, data) => {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
})
app.listen(3000, () = > {console.log('listen to 3000');
});
// Socketio depends on the NodeJS server
const io = require('socket.io')(app);
// Listen for user connection events
//socket indicates the connection of the user
// Socket emit triggers an event. If you send data to the browser, you need to trigger an event registered by the browser
// Socket on registers an event. If you need to obtain browser data, you need to register an event and wait for the browser to trigger it
io.on('connection', socket => {
console.log('New user Connection');
// Emit data to the browser (' sent event ',' sent event ')
socket.emit('send', {name: 'jack'});
// Get the data sent by the browser and register the event as long as it is the same as the event that was triggered
socket.on('clientData',data=>{
console.log(data); })});Copy the code
index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
hello
<script src="/socket.io/socket.io.js"></script>
<script>
// Connect to the socket service
let socket = io('http://localhost:3000');
// The browser registers the server
socket.on('send',data =>{
console.log(data);
});
// Send data to the server
socket.emit('clientData', {name:'jack'});
</script>
</body>
</html>
Copy the code
Send data using Emit, accept data using ON. When the browser or server sends data to the other party, it only needs to trigger the corresponding event.
2.2 Socketio based on express framework
Install express
npm i express
app.js
const app = require('express') ();const server = require('http').Server(app);
const io = require('socket.io')(server);
server.listen(3000, () = > {console.log('listen to 3000');
});
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
socket.on('clientData', (data) => {
console.log(data);
});
});
Copy the code
index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
hello
<script src="/socket.io/socket.io.js"></script>
<script>
let socket = io('http://localhost:3000');
socket.emit('clientData', { name: 'jack' });
</script>
</body>
</html>
Copy the code
Use socketio to develop chat rooms
Import a static resource directory structure
1. Set up the server
app.js
/* Start the chat room server program */
const app = require('express') ();const server = require('http').Server(app);
const io = require('socket.io')(server);
server.listen(3000, () = > {console.log('Server started successfully');
});
// Handle static resources and set the public directory to static resources
app.use(require('express').static('public'));
app.get('/', (req, res) => {
// Redirect to the home page
res.redirect('/index.html');
});
io.on('connection', (socket) => {
console.log('New user Connection');
});
Copy the code
2. Login function
2.1 Login verification
js/index.js
/* Main functions of the chat room */
/ / socketio connection
let socket = io('http://localhost:3000');
/* Login function */
// Select the profile picture and register a click event with Li. Add now class addClass and siblings and remove the siblings from other Li classes
$('#login_avatar li').on('click'.function () {$(this).addClass('now').siblings().removeClass('now');
});
// Click the button to log in
$('#loginBtn').on('click'.function () {
// Get the user name, remove the space
let username = $('#username').val().trim();
if(! username) { alert('Please enter a user name');
return
}
Now select li attr(' SRC ') to get the profile picture path
let avatar = $('#login_avatar li.now img').attr('src');
// Communicate with the server and transfer the user name and profile picture to the server
socket.emit('login', {username: username,
avatar: avatar
});
});
// Listen for failed login requests
socket.on('loginError',data=>{
alert('Login failed, user name already exists');
});
// Listen for successful login requests
socket.on('loginSuccess',data=>{
alert('Login successful');
});
Copy the code
app.js
// Save all users who have logged in
const users = [];
// Listen for user connections
io.on('connection', (socket) => {
console.log('New user Connection');
// Listen for login requests sent by the client
socket.on('login',data=>{
// Check whether the name is the same as the name in the array
let user = users.find(item= > item.username === data.username);
if (user) {
// The user exists. Login failed
socket.emit('loginError', {msg:'Login failed'});
}else {
// If the user does not exist, save the user to the array
users.push(data);
socket.emit('loginSuccess',data); }}); });Copy the code
2.2 Personal information is displayed after login
js/index.js
// Listen for successful login requests
socket.on('loginSuccess',data=>{
// show the chat box, hide the chat window fadeOut,fadeIn fadeIn effect
$('.login_box').fadeOut();
$('.container').fadeIn();
// Set the user information after successful login
$('.avatar_url').attr('src',data.avatar);
$('.user-list .username').text(data.username);
});
Copy the code
2.3. Broadcast new users joining a group chat
app.js
// Listen for user connections
io.on('connection', (socket) => {
console.log('New user Connection');
// Listen for login requests sent by the client
socket.on('login',data=>{
// Check whether the name is the same as the name in the array
let user = users.find(item= > item.username === data.username);
if (user) {
// The user exists. Login failed
socket.emit('loginError', {msg:'Login failed'});
}else {
// If the user does not exist, save the user to the array
users.push(data);
socket.emit('loginSuccess',data);
// broadcast message, someone has joined the chat room IO. Emit broadcast event
io.emit('addUser',data); }}); });Copy the code
js/index.js
// Listen for requests for new users to join
socket.on('addUser', data => {
// Add a system message
$('.box-bd').append(
`<div class="system">
<p class="message_system">
<span class="content">${data.username}</span> </p> </div> ')});Copy the code
Display user list and user number
app.js
// Listen for user connections
io.on('connection', (socket) => {
console.log('New user Connection');
// Listen for login requests sent by the client
socket.on('login',data=>{
// Check whether the name is the same as the name in the array
let user = users.find(item= > item.username === data.username);
if (user) {
// The user exists. Login failed
socket.emit('loginError', {msg:'Login failed'});
}else {
// If the user does not exist, save the user to the array
users.push(data);
socket.emit('loginSuccess',data);
// broadcast message, someone has joined the chat room IO. Emit broadcast event
io.emit('addUser',data);
// Displays the current number of people in the chat room
io.emit('userList',users); }}); });Copy the code
js/index.js
/ Listen for user list messages socket.on('userList', data => {
// Display the data in userList dynamically in the left menu
$('.user-list ul').html(' '); // Set the list to null at the end of each loop, otherwise the stack will repeat
data.forEach(item= >{$('.user-list ul').append(
`<li class="user">
<div class="avatar"><img src="${item.avatar}" alt=""/></div>
<div class="name">${item.username}</div>
</li>`)})// Display the number of users
$('#userCount').text(data.length);
});
Copy the code
3, leave the chat room function
app.js
// Listen for user disconnect disconnect event
socket.on('disconnect', () = > {// Delete the current user from users. FindIndex finds the subscript of the current user
let idx = users.findIndex(item= > item.username === socket.username);
/ / delete
users.splice(idx,1);
// Broadcast someone leaving the chat room
io.emit('delUser', {username:socket.username,
avatar: socket.avatar
})
/ / update the userList
io.emit('userList', users);
})
Copy the code
js/index.js
// Listen for delete user messages
socket.on('delUser', data => {
// Add a system message
$('.box-bd').append(
`<div class="system">
<p class="message_system">
<span class="content">${data.username}< span style = "box-sizing: border-box! Important; word-wrap: break-word! Important)});Copy the code
4. Chat function
4.1 Implementation of basic chat function
app.js
// Listen to chat messages
socket.on('sendMessage',data=>{
console.log(data);
// Broadcast the message if there is a database where the data is stored
io.emit('receiveMessage',data);
})
Copy the code
js/index.js
// Define two global variables to hold username and Avatar
var username;
var avatar;
// Save the user information after the successful login
username = data.username;
avatar = data.avatar;
// Chat function
$('.btn-send').on('click', () = > {// Get the chat content
let content = $('#content').val().trim();
// Empty the chat area
$('#content').val(' ');
// Check whether the data is empty
if(! content) {return alert('Please enter content');
}
// Send to the server
socket.emit('sendMessage', {
msg: content,
username: username,
avatar: avatar
})
})
// Listen to chat messages
socket.on('receiveMessage', data => {
// Display the received message in the chat window
// Determine whether the information is your own or someone else's
if (data.username === username) {
// Your own message
$('.box-bd').append(
` <div class="message-box">
<div class="my message">
<img class="avatar" src="${data.avatar}" alt=""/>
<div class="content">
<div class="bubble">
<div class="bubble_cont">${data.msg}</div>
</div>
</div>
</div>
</div>`
);
} else {
// Other people's news
$('.box-bd').append(
`<div class="message-box">
<div class="other message">
<img class="avatar" src="${data.avatar}" alt=""/>
<div class="content">
<div class="nickname">${data.username}</div>
<div class="bubble">
<div class="bubble_cont">${data.msg}</div>
</div>
</div>
</div>
</div>`); }})Copy the code
4.2. Automatically scroll to the bottom after sending the message
The element.scrollintoView () method lets the current Element scroll into the viewable area of the browser window.
- If true, the top of the element is aligned with the top of the visible area of the scroll where it is located.
- If false, the bottom of the element is aligned with the bottom of the visible area of the scroll where it is located.
js/index.js
function scrollIntoView() {
// Use scrollIntoView() to scroll to the bottom,children(':last') to find the last child, and get(0) to get the ELEMENT's DOM object
$('.box-bd').children(':last').get(0).scrollIntoView(false);
}
Copy the code
Every listener that sends a message uses the scrollIntoView method, including system notifications
4.3 Send pictures
app.js
// Send the image change to indicate the selection of the file
$('#file').on('change'.function () {
// Get the uploaded file
var file = this.files[0];
// Send the file to the server, use H5 function fileReader, read the uploaded file
var fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = function () {
socket.emit('sendImage', {
username: username,
avatar: avatar,
img: fr.result
})
}
})
// Listen for pictures
socket.on('receiveImage', data => {
// Display the received message in the chat window
// Determine whether the information is your own or someone else's
if (data.username === username) {
// Your own message
$('.box-bd').append(
` <div class="message-box">
<div class="my message">
<img class="avatar" src="${data.avatar}" alt=""/>
<div class="content">
<div class="bubble">
<div class="bubble_cont">
<img src="${data.img}">
</div>
</div>
</div>
</div>
</div>`
);
} else {
// Other people's news
$('.box-bd').append(
`<div class="message-box">
<div class="other message">
<img class="avatar" src="${data.avatar}" alt=""/>
<div class="content">
<div class="nickname">${data.username}</div>
<div class="bubble">
<div class="bubble_cont">
<img src="${data.img}">
</div>
</div>
</div>
</div>
</div>`
);
}
// Wait for the image to load before scrolling
$('.box-bd img:last').on('load'.function () {
scrollIntoView();
});
});
Copy the code
js/index.js
// Accept the picture information
socket.on('sendImage',data=>{
// Broadcast the message if there is a database where the data is stored
io.emit('receiveImage',data);
})
Copy the code
4.3. Sending emojis
Using Jquery emoji plugin
Introduce CSS in index.html
<link rel="stylesheet" href="lib/jquery-mCustomScrollbar/css/jquery.mCustomScrollbar.min.css"/>
<link rel="stylesheet" href="lib/jquery-emoji/css/jquery.emoji.css"/>
Copy the code
The introduction of js
<script src="lib/jquery-mCustomScrollbar/script/jquery.mCustomScrollbar.min.js"></script>
<script src="lib/jquery-emoji/js/jquery.emoji.min.js"></script>
Copy the code
Emoji () parameter reference
js/index.js
// Send emojis
// Initialize jQuery-emoji plugin
$('.face').on('click'.function () {$('#content').emoji({
// The button that triggers the emoji
button: '.face'.showTab: false.animation: 'slide'.position: 'topRight'.icons: [{
name: "QQ expression".path: ".. /lib/jquery-emoji/img/qq/".maxNum: 91.excludeNums: [41.45.54].file: ".gif"}}]); })Copy the code
Note: < div > < div style = “color: RGB (50, 50, 50); If you can’t get the contents of the div using the original val, use HTML () instead
Screenshot of project running
GitHub: github.com/812467457/w…