WebSocket
Using the most recent project to WebSocket, here we summarize the problems encountered and the methods used
What is at first introduced WebSocket
WebSocket is a network transport layer protocol, can be full duplex communication over a single TCP connection,
the application layer of the OSI model, the server allows WebSocket actively push the data to the client. Browser arms and I just need to complete a handshake, you can create a persistent connection between the two, and two-way data transmission.
Why use WebSocket (WebSocket What are the advantages to traditional HTTP)
- Client and server only establish a TCP connection, you can use fewer connections
- The server may push data to the client, the HTTP request response pattern than the more flexible, more efficient
- More lightweight protocol header, reducing the amount of data transferred
WebSocket handshake
When a client establishes a connection, initiated by HTTP request packets
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Differentiated portion HTTP request protocol:
Upgrade: websocket
Connection: Upgrade
These two fields representing a request for the upgrade server WebSocket.
Sec-WebSocket-Key
Safety check:
Sec-WebSocket-Key value is randomly generated Base64 encoded string. After the server receives the character string which is connected 258EAFA5-E914-47DA-95CA-C5AB0DC85B11, line into dGhlIHNhbXBsZSBub25jZQ == 258EAFA5-E914-47DA-95CA-C5AB0DC85B11, and compute the result sha1 secure hash algorithm, performing Base64 encoding and finally returned to the client.
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
The above two fields specify the sub-protocol and version number
After the server processed the request, the response message as follows:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Status code 101 indicates handover protocol, the application layer protocol WebSocket update protocol, and application of a new protocol on the current socket
Sec-WebSocket-Accep:
It represents server-based string Sec-WebSocket-Key generated
Sec-WebSocket-Protocol:
It represents the end-use agreement
Client code
let ws = new WebSocket('ws://192.168.10.40:3000/')
ws.onopen = mes=>{
console.log(mes,'aaa')
}
Server code
const net = require('net');
const crypto = require('crypto');
const wsGUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
net.createServer(function(socket) {
socket.on('data', function(buffer) {
// data 是buffer需要转化
const data = buffer.toString(),
key = getWebSocketKey(data),
acceptKey = crypto.createHash('sha1').update(key + wsGUID).digest('base64'),
headers = [
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: ' + acceptKey
];
socket.write(headers.concat('','').join('\r\n'));
})
}).listen(3000)
function getWebSocketKey(dataStr) {
var match = dataStr.match(/Sec\-WebSocket\-Key:\s(.+)\r\n/);
if (match) {
return match[1];
}
}
Client API
1.websocket Constructor
WebSocket object as a constructor to create a new instance WebSocket.
var ws = new WebSocket('ws://localhost:8080');
After executing the above statement, the client will connect to the server. The picture below is a list of all the properties and methods of an object instance
2.webSocket.readyState
readyState property returns an instance of the object's current state, there are four.
console.log(ws.readyState) // 我们可以输入看当前是什么状态
- CONNECTING: 0, it means is connected.
- OPEN: A value of 1 indicates a successful connection, the communication can be.
- CLOSING: value 2, it indicates that the connection is closed.
- CLOSED: a value of 3, indicates that the connection has been closed, or open the connection fails.
3.webSocket.onopen
onopen object attribute instance, specify a callback function for the successful connection.
ws.onopen = function () {
ws.send('Hello Server!');
}
If you want to specify multiple callback functions, you can use
addEventListener
the method.
ws.addEventListener('open', function (event) {
ws.send('Hello Server!');
});
4.webSocket.onclose
onclose object attribute instance, the callback function for the designated connection is closed.
ws.onclose = function(event) {
var code = event.code;
var reason = event.reason;
var wasClean = event.wasClean;
// handle close event
};
5.webSocket.onmessage
onmessage object attribute instance, specify a callback function for the received server data
ws.onmessage = function(event) {
var data = event.data;
// 处理数据
};
ws.addEventListener("message", function(event) {
var data = event.data;
// 处理数据
});
We can use this callback function to handle the returned data is equivalent to what we usually use axios successful data then return method
6.webSocket.send()
Examples of objects send () method for transmitting data to the server
ws.send('your message');
7.webSocket.bufferedAmount
bufferedAmount object attribute instance, it indicates how many bytes of binary data is not sent. It can be used to determine whether to end the transmission.
var data = new ArrayBuffer(10000000);
socket.send(data);
if (socket.bufferedAmount === 0) {
// 发送完毕
} else {
// 发送还没结束
}
8.webSocket.onerror
onerror property of an object instance, the callback function for the specified error.
socket.onerror = function(event) {
// handle error event
};
socket.addEventListener("error", function(event) {
// handle error event
});
Complete example
Server
import userInfoModel from '../model/userinfo';
import addendanceInfoModel from '../model/addentance';
import Websocket from 'ws';
import * as http from 'http';
const wss = new Websocket.Server({port: 3004});
wss.on('connection',function(ws:Websocket,req:http.IncomingMessage) {
ws.on('message',async function(){
try{
// 获取基本数据
const userData = await userInfoModel.find();
ws.send(JSON.stringify(userData));
// 获取出勤数据
const addendanceData = await addendanceInfoModel.find();
ws.send(JSON.stringify(addendanceData))
}catch(err){
ws.close()
}
})
})
The front websocket
// Ws 封装一系列websock方法
// getInstance 获取当前类的实例
// initConnect 初始化连接,返回promise,连接成功resolve,失败reject
// send 发送数据,包括断开重新连接
export default class Ws{
constructor(){
// 初始化连接
this.initConnect()
}
static getInstance() {
if(!this.instance){
this.instance = new Ws()
}
return this.instance;
}
initConnect(){
// 创建ws实例
return new Promise((resolve,reject)=>{
this.ws = new WebSocket('ws://192.168.10.40:3004/');
this.ws.onmessage = event => this.message(JSON.parse(event.data));
this.ws.onopen = event => resolve(event);
this.ws.onclose = event => reject(event);
})
}
async send(data){
// 如果为连接断开就重新连接
if(this.ws.readyState == 3 ){
// 初始化连接
await this.initConnect();
// 连接成功发送消息
data && this.ws.send(JSON.stringify(data))
}else{
// 发送消息
data && this.ws.send(JSON.stringify(data))
}
}
close() {
if(this.ws.readyState == 3){
return;
}
this.ws.close();
}
}
A front end assembly portion
<script>
import Ws from '@/assets/websocket.js';
export default {
name: 'HelloWorld',
mounted() {
this.ws = Ws.getInstance();
this.ws.message = this.onmessage;
},
methods:{
onmessage(data) {
console.log(data,'数据')
},
OnClick() {
this.ws.send({})
}
}
}
</script>
websocket encountered pit
If the data is sent to the rear end of the front end, a rear end response time is too long, the read time may exceed the server, troubleshoot problems, and finally found a timeout nginx Agent
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s:
Set the read time-out from the back end, default 60s, he decided nginx will wait how long to get a response request, nginx will close the connection timeout
proxy_send_timeout 60s;
Sends a request to set the timeout upstream server, if the upstream server 60s no response is received, the connection is closed Nginx
We just need to find students to help us put the operation and maintenance agency prolonged, it would not have a timeout
We in the code can also be set to disconnect and reconnect
initConnect(){
// 创建ws实例
return new Promise((resolve,reject)=>{
this.ws = new WebSocket('ws://192.168.10.40:3004/');
this.ws.onmessage = event => this.message(JSON.parse(event.data));
this.ws.onopen = event => resolve(event);
this.ws.onclose = event => reject(event);
})
}
async send(data){
// 如果为连接断开就重新连接
if(this.ws.readyState == 3 ){
// 初始化连接
await this.initConnect();
// 连接成功发送消息
data && this.ws.send(JSON.stringify(data))
}else{
// 发送消息
data && this.ws.send(JSON.stringify(data))
}
}
In the above code, the rear end of each transmission data to judge whether the current websocket connection state, when the state is 3 (disconnected), it is reconnected to the rear end of the data transmission connection is successful.