To implement a one-to-one instant chat application, it is important that messages can be delivered in real time. One solution is known as the Websocket protocol. In this article, we use a framework in Node.js socket. IO to implement it.
Results the preview
Let’s take a look at our final result, which looks like this:
You can also enter one of the following urls into your browser:
http://120.27.239.212:30010/?sender= zhao & receiver can & receiver = = can http://120.27.239.212:30010/?sender= zhaoCopy the code
Technology selection
- Boostrap was also used to implement our page layout and some style rendering.
- Back-end: node.js + Express + socket.io.
The front-end implementation
HTML Page layout
The HTML layout of the chat page is uncomplicated and is roughly divided into three layers, as follows:
- Chat-header: indicates the header of the chat interface.
- Chat-content: Displays the overall content of the chat. Now all you see is an empty div that will operate on the DOM to insert the message content into the chat body after sending or receiving the chat message.
- Chat-bottom: The chat-bottom shows the content input window and send button of our chat window.
<div class="container">
<div class="chat-header row">
<span class="col-xs-2 chat-header-left glyphicon glyphicon-menu-left"></span>
<span class="col-xs-8 chat-header-center" id="chatHeaderCenter"></span>
<span class="col-xs-2 chat-header-right glyphicon glyphicon-option-horizontal"></span>
</div>
<div class="chat-content" id="chatContent"></div>
<div class="chat-bottom row">
<span class="col-xs-10 col-md-11 input-text"><input type="text" class="form-control " id="inputText" placeholder="Please enter what you want to send..."></span>
<span class="col-xs-2 col-md-1 span-submit">
<input class="btn btn-default btn-primary input-submit" id="sendBtn" data-dismiss="alert" type="submit" value="Send">
</span>
</div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="./js/chat.js"></script>
Copy the code
Socket.io Client
The client first creates a socket object. The first argument to IO () is the URL of the linked server, which is window.location by default. The Socket client and server have two functions on() and emit(), which are also the core functions. The two functions can easily achieve two-way communication between the client and server.
- Emit: Emit an event. The first parameter is the name of the event. The second parameter is the data to be sent to the other end.
- On: Registers an event to listen for events triggered by the emit.
// js/chat.js
const socket = io();
socket.on('connect', () => {
socket.emit('online', query.sender);
});
socket.on('reply_private_chat', replyPrivateMessage); .Copy the code
Send a message in the client, is to listen to the onclick event or return event of the send button, do some processing of the message sent through socket.emit to the server, from the server to transfer to another client.
The front-end part of the code for more details, not listed here, can be Clone on Github down to view, the end of the code sample address.
const chatHeaderCenter = document.getElementById('chatHeaderCenter');
const inputText = document.getElementById('inputText');
const sendBtn = document.getElementById('sendBtn');
chatHeaderCenter.innerText = query.receiver;
sendBtn.onclick = sendMsg;
inputText.onkeydown = sendMsgByEnter;
function sendMsg() {
const value = inputText.value;
if(! value)return alert('Message is required! ');
const message = { sender: query.sender, receiver: query.receiver, text: value };
socket.emit('private_chat', message, data => {
renderMessage(data, true);
});
inputText.value = ' '; }...Copy the code
The backend implementation
Use Express to set up the service
Use Express to build our back-end service, create an app.js inside listening to port 30010, and load our client page.
// app.js
const express = require('express');
const app = express();
const path = require('path');
const server = require('http').createServer(app);
const PORT = 30010;
app.use(express.static(path.join(__dirname, '.. / '.'public')));
server.listen(PORT, () => console.log(`Server is listening on ${PORT}`));
Copy the code
The introduction of the Socket. IO
Now that we’ve set up a simple Express service, let’s introduce our custom io.js.
// app.js
require('./io.js')(server);
Copy the code
When a server object is passed in to the socket. IO object, it will receive an I/O object from the server. The connection event will be registered synchronously. The socket of the connection callback function refers to the connection established between the client and the server.
There are also online, private_chat, disconnect events, some of which are provided by the system, and some of which are customized by us, which we’ll cover later.
const _ = require('underscore');
const moment = require('moment');
const userData = require('./users.json');
const USER_STATUS = ['ONLINE'.'OFFLINE'];
const users = {};
module.exports = server= > {
const io = require('socket.io')(server);
io.on('connection', socket => {
socket.on('online', ...)
socket.on('private_chat',...). ; socket.on('disconnect',...). ; }); }Copy the code
Online notice
On (‘online’) is an event defined by us. When the client goes online, it is triggered to tell us the user information of the current client. The socket.id is saved to establish the mapping relationship between the user and socket.id for subsequent private chat. Here the socket.id is changed every time the client dislinks.
socket.on('online', username => {
socket.username = username;
users[username] = {
socketId: socket.id,
status: USER_STATUS[0]}; })Copy the code
Receiving or sending private chat messages
On (‘private_chat’) is also an event defined by us. After receiving a message from a client, we process the message and determine whether the recipient is online. If the recipient is online, we use socket.id to find the corresponding socket and push the message to the recipient. The key point here is socket.to().emit().
socket.on('private_chat', (params, fn) => {
const receiver = users[params.receiver];
params.createTime = moment().format('YYYY-MM-DD HH:mm:ss');
const senderData = _.findWhere(userData, { username: params.sender });
params.senderPhoto = (senderData || {}).photo;
if(! params.senderPhoto) {const senderLen = params.sender.length;
params.senderPhotoNickname = params.sender.substr(senderLen - 2)
}
fn(params);
if (receiver && receiver.status === USER_STATUS[0]) {
socket.to(users[params.receiver].socketId).emit('reply_private_chat', params);
} else {
console.log(`${params.receiver}No online `);
// You can do some offline message push processing}});Copy the code
disconnect
Triggered when the link is disconnected. Reason indicates the reason why the client or server is disconnected. In this event we will also change the reason for the disconnection.
socket.on('disconnect', reason => {
if (users[socket.username]) users[socket.username].status = USER_STATUS[1];
});
Copy the code
Code & Deployment
I’ve packaged the above example as a Docker image, and you can pull it up and deploy it yourself by executing the following command.
docker pull docker.io/qufei1993/private-chat-socketio
Copy the code
Example code:
- Making: github.com/qufei1993/e…
Demo online experience:
http://120.27.239.212:30010/?sender= zhao & receiver can & receiver = = can http://120.27.239.212:30010/?sender= zhaoCopy the code
conclusion
Socket. IO has been encapsulated very well, using it to develop an instant chat application more work needs us to access their own business logic, this article is just a chat system tip of the iceberg, there are a lot of need to do, interested friends welcome to follow, will continue to share some other functions.