socket.io
Introduction to the
It is often difficult to write chat applications using popular Web application stacks, such as PHP. It involves polling the server to detect changes and tracking time stamps, and this implementation is slow.
Most real-time chat systems are typically built on WebSocket, specifically socket.io. WebSocket provides a two-way communication mechanism for the client and server.
This means that the server can push messages to the client. Whenever you post a message, the server can receive the message and push it to other clients connected to the server.
Web framework
Start by creating an HTML page to provide the form and message list. We used The Node.js-based Web framework Express. Make sure node.js is installed.
Start by creating a package.json to describe our project. You are advised to create an empty directory.
Express is already installed. We will now create a new index.js file to create the application.
var app = require('express') (); var http = require('http').Server(app);
app.get('/'.function(req, res){
res.send('<h1>Hello world</h1>');
});
http.listen(3000, function(){
console.log('listening on *:4000');
});
Copy the code
This code does the following:
Express initializes app as a callback function for the HTTP server.
Defines a route/to handle home page access.
Make the HTTP server listen on port 4000.
HTML server
Currently in index.js we return an HTML string with res.send. If we put the entire APPLICATION’s HTML code in the application code, the structure of the code would get messy. Instead, create a new index.html file as the server response.
Now we’ll use sendFile to refactor the previous callback:
app.get('/'.function(req, res){
res.sendFile(__dirname + '/index.html');
});
Copy the code
Index.html reads as follows:
<! doctype html> <html> <head> <title>Socket.IO chat</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font: 13px Helvetica, Arial; } form { background:# 000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
Copy the code
integrationSocket.IO
Socket.IO consists of two parts:
- A server for integrating (or mounting) into node.js HTTP server: socket.io
- A client loaded into the browser: socket.io-client
You can use both parts of this
npm install –save socket.io
npm install –save socket.io-client
var app = require('express') (); var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/'.function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection'.function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
Copy the code
We initialized an instance of socket. IO by passing in an HTTP (HTTP server) object. The Connection event is then listened on to receive sockets and print the connection information to the console.
Add the following to the index.html tag:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
Copy the code
This loads socket.io. Socket. IO exposes an IO global variable and then connects to the server.
Note that we didn’t specify any URL when we called IO (), because by default it will try to connect to the host that provided the current page.
Reload the server and website, and you’ll see the console print “A user Connected.”
Each socket also fires a special Disconnect event:
io.on('connection'.function(socket){
console.log('a user connected');
socket.on('disconnect'.function(){
console.log('user disconnected');
});
});
Copy the code
Triggering event
The core idea of socket. IO is to allow you to send and receive arbitrary events and arbitrary data. Any object that can be encoded as JSON can be used for transport. Binary data is also supported.
The implementation here is that when a user enters a message, the client sends a Chat Message event and the server receives a Chat Message event. The script part of the index.html file should now read:
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val(' ');
return false;
});
});
</script>
Copy the code
radio
The next goal is to get the server to send messages to other users.
To send events to each user, socket. IO provides the IO. Emit method:
io.emit(‘some event’, { for: ‘everyone’ });
For simplicity, we send the message to all users, including the sender.
io.on('connection'.function(socket){
socket.on('chat message'.function(msg){
io.emit('chat message', msg);
});
});
Copy the code
Usage summary
The service side
1. The connection
Listening for a client connection, the callback function passes the socket for the connection
io.on('connection'.function(socket));
Copy the code
Radio 2.
(1) Broadcast messages to all clients
io.sockets.emit('String',data);
Copy the code
(2) Broadcast messages to clients other than yourself
socket.broadcast.emit("msg",{data:"hello,everyone"});
Copy the code
(3) Send messages to the specified client
io.sockets.socket(socketid).emit('String', data);
Copy the code
3. Sent messages
(1) Monitor the client
socket.on('String'.function(data));
Copy the code
(2) Send messages to the client of the socket
socket.emit('String', data);
Copy the code
Group 4.
io.of('/some').on('connection'.function (socket) {
socket.on('test'.function (data) {
socket.broadcast.emit('event_name'{}); }); });Copy the code
Advanced – Processing the data sent by the user
A, redis
What is Redis?
REmote DIctionary Server(Redis) is a key-value storage system written by SalvatoreSanfilippo.
Redis is an open source, network-enabled, memory-based and persistent logging, key-value database written in ANSI C, BSD compliant, and provides multiple language apis.
It is often called a data structure server because values can be of the types String, hash, list, set, and sorted sets.
Data types in Redis
Map hashmap: A Hash table (also called a Hash table) is a structure that accesses data stored in memory by Key.
List: A list is a finite sequence of data items, that is, a collection of data items arranged in a certain linear order. (Redis uses bidirectional linked list implementation)
Sets: Similar to what you learned in middle school. The characteristic is that the elements in the set cannot be unique repeatedly. The cut inside is disordered
Sorted sets: Sorted sets are also collections, but the internal data is sorted.
Redis installation
Redis installation link
npm redis
Redis usage method
0, establish node-redis client connection NPM I redis –save
Var redis = require('redis');
var client = redis.createClient('6379'.'127.0.0.1'); // Redis link error client.on("error".function(error) { console.log(error); }); // redis authentication (reids.conf authentication is disabled, this item is not required) // client.auth("foobared");
module.exports = {
client:client
}
Copy the code
1. Access to set
const {client} = require('./redis')
client.set('key001'.'AAA'.function (err, response) {
if (err) {
console.log("err:", err);
} else {
console.log(response);
client.get('key001'.function (err, res) {
if (err) {
console.log("err:", err);
} else {
console.log(res);
client.end(true); }}); }});Copy the code
2. Hash access
There are two methods for setting values and extracting data from a hash set:
const {client} = require('./redis')
client.hset('filed002'.'key001'.'wherethersisadoor'.function (err, res) {
if (err) {
console.log(err);
} else {
console.log('res:', res);
client.hget('filed002'.'key001'.function (err, getRslt) {
if (err) {
console.log(err);
} else {
console.log('getRslt:', getRslt);
client.end(true); }}); }});Copy the code
Note: when the hget method does not find the specified key under the specified field, it passes the callback function NULL instead of null characters or undefined.
※ Sets the value of multiple keys. When the value is set, the value of single or multiple keys specified in the specified field can be obtained
const {client} = require('./redis')
var qe = {a: 2, b:3, c:4};
client.hmset('field003', qe, function(err, response) {
console.log("err:", err);
console.log("response:", response);
client.hmget('field003'['a'.'c'].function (err, res) {
console.log(err);
console.log(res);
client.end(true);
});
});
Copy the code
The hmset method can be JSON data, but the key value in redis is stored as a string. If there are more than one JSON data layer, the value will be ‘[object object]’.
The return value of the hmGET method is an array, in which the order of elements corresponds to the order in the key array of parameters. If there is a key in the parameter array that does not exist in the field, the corresponding position of the return result array will be null, that is, whether the value can be retrieved or not, The positions of the elements in the result array always correspond to the positions of the elements in the key array of the parameters.
Keys (fieldname, callback); Note that this method can take a long time if there are many keys in the hash.
3. Linked list is suitable for storing new lpush key value [value…] Rpush key value [value…] Add an element to the right of the key. Lpop Key removes the first element on the left of the key. Rpop Key removes the first element on the right of the key
const {client} = require('./redis')
client.lpush('test', 12345, function(err, response) {
if(err){
console.log("err:", err);
}else{
console.log("response:", response);
client.rpop('test'.function (err, res){
if(err){
console.log(err);
}else{
console.log(res);
client.end(true); }}); }});Copy the code
redis-cli
Socket. IO access redis and create multiple namespaces
How to use
const io = require('socket.io') (3000); const redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
Copy the code
Change index.js to
const app = require('express') (); const http = require('http').Server(app);
const io = require('socket.io')(http);
const redis = require('socket.io-redis');
const {client} = require('./test/redis')
const moment = require('moment')
app.get('/'.function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.adapter(redis({host: 'localhost', port: 6379}));
var nameBox = ['/chatroom'.'/live'.'/vod'.'/wechat'.'/broadcast'];
for(var item in nameBox){
var nsp = io.of(nameBox[item])
socketMain(nsp,nameBox[item])
}
function socketMain(nsp,roomName) {
nsp.on('connection'.function (socket) {
console.log('a user connected')
socket.on('disconnect'.function(){
console.log('user disconnected');
});
socket.on('chat message'.function(msg){
var data = {"socketid":socket.id,"cid":roomName,"msg":msg,createTime:moment().unix()};
client.lpush('message',JSON.stringify(data),redis.print)
console.log('message: ' + msg);
});
})
}
http.listen(4000, function(){
console.log('listening on *:4000');
});
Copy the code
index.html
var socket = io.connect("http://127.0.0.1:4000/live");
Copy the code
Access to redis
client.lpush('message',JSON.stringify(msg),redis.print)
Copy the code
Second, another server to take redis data for processing
Question: How do two services communicate with each other?
Answer: Use socket.io-client. The steps are as follows:
Socket. IO -client var IO = require('socket.io-client'); Var socket = IO. Connect (socket = IO. Connect (socket = IO.'ip+'/live' ', {reconnect: true}); 3. Through this simulated client, communicate with the main program socket.emit('redisCome', result);
Copy the code
Modify the redis. Js
module.exports = {
client:client,
ip:'http://127.0.0.1:4000'
}
Copy the code
New sclient. Js
const io = require('socket.io-client');
const async = require('async');
const moment = require('moment');
const redis = require('redis');
const {client,ip} = require('./test/redis');
const domain = require('domain');
const debug = require('debug') ('socket-client:main');
var origin = io.connect(ip+'/', {reconnect: true});
var chatroom = io.connect(ip+'/chatroom', {reconnect: true});
var live = io.connect(ip+'/live', {reconnect: true});
var vod = io.connect(ip+'/vod', {reconnect: true});
var wechat = io.connect(ip+'/wechat', {reconnect: true});
var broadcast = io.connect(ip+'/broadcast', {reconnect: true});
var namBox = {root:origin,chatroom:chatroom,live:live,vod:vod,wechat:wechat,broadcast:broadcast};
var reqDomain = domain.create();
reqDomain.on('error'.function (err) {
console.log(err);
try {
var killTimer = setTimeout(function () {
process.exit(1);
}, 100);
killTimer.unref();
} catch (e) {
console.log('error when exit', e.stack); }}); reqDomain.run(function () {
compute();
});
process.on('uncaughtException'.function (err) {
console.log(err);
try {
var killTimer = setTimeout(function () {
process.exit(1);
}, 100);
killTimer.unref();
} catch (e) {
console.log('error when exit', e.stack); }});function compute() {
client.llen('message'.function(error, count){
if(error){
console.log(error);
}else{
if(count){
//console.log('-------------has count',time);
popLogs();
process.nextTick(compute);
}else{
//console.log('-------------empty',time);
setTimeout(function(){ compute(); }, 100); }}}); }function popLogs(){
var time = moment().unix();
console.log('-------------dealStart-------------',time);
client.rpop('message'.function(err,result){
if(err){
console.log(err);
}else{
var result = JSON.parse(result);
try{
var cid = result.cid;
//console.log('place',result.place);
}catch(e){
console.log('empty data cid',result);
return;
}
console.log(' start '+' nsp: '+cid +' time: '+time);
if(namBox[cid]){
console.log(result);
namBox[cid].emit('redisCome',result); }}}); }Copy the code
Modify index.js to add redisCome listening events
/* Receive messages from redis */ socket.on('redisCome'.function (data) {
console.log('-------------redisCome',data.msg);
try{
var msg = data.msg
}catch(e){
var msg = ' ';
}
console.log(data);
nsp.emit('message.add',msg);
});
Copy the code
Modified index. HTML
socket.on('message.add'.function (msg) {
$('#messages').append($('<li>').text(msg));
})
Copy the code
3. Add user sent message verification
To increase the security of information, we can filter the information sent by users for sensitive words, SQL injection attacks, XSS attacks and so on, using async step by step operation process
Modify sclient. Js
async.waterfall([
function (done) {
user.messageDirty({msg:result.msg},function(err,res){
//console.log('sql done'/*,res*/);
done(err,res);
});
},
function (res,done) {
user.messageValidate({msg:result.msg},function(err,res){
//console.log('key done'/*,res*/);
done(err,res); }); }].function (err,res) {
if(err){
console.log('err!!!! ',err,result);
namBox[cid].emit('messageError',err);
}else{
if(namBox[cid]) {
console.log(result);
namBox[cid].emit('redisCome', result); }}})Copy the code
Modified index. Js
/* Receive redis error message */ socket.on('messageError'.function(err){
console.log('messageError');
try{
nsp.emit('message.error',err.msg);
}catch(e){
}
});
Copy the code
Modified index. HTML
Mysql storage
Install the mysql database locally. 2. Download the Node mysql package
npm install mysql --save
Copy the code
3. Connect to the database to establish a connection pool
var mysql = require('mysql');
var pool = mysql.createPool({
host: 'localhost',
user:'root',
password:'123456',
database : 'danmaku'
});
var query = function(sql,options,callback){
pool.getConnection(function(err,conn){
if(err){
callback(err,null,null);
}else{
conn.query(sql,options,function(err,results,fields){// Release connection conn.release(); // Event-driven callback(err,results,fields); }); }}); };Copy the code
The new query. Js
var {query} = require("./test/redis");
query("select * from demo".function(err,results,fields){
//do something
if(err){
console.log(err)
}else {
console.log(results)
}
});
Copy the code
The new insert. Js
var {query} = require("./test/redis");
const moment = require('moment')
query('insert into demo(message,createTime) values(? ,?) ',[123,moment().unix()],function(err,results,fields){
//do something
if(err){
console.log(err)
}else {
console.log(results)
}
});
Copy the code
mysql -u root -p use danmaku; select * from demo;
4. Add the repository step to the program
Danmaku player
ABPlayerHTML5
The project address
Here’s the link