使用nodejs 开发websocket消息分发系统
websocket使用事件触发机制传输密集传输数据,跟nodejs的事件机制相同,比起早期comet技术使用的http响应式更为高效,客户端不用重复的与服务端握手更加节约服务器性能。
1、在客户端调用
socket事件
message 消息接收
open 与服务器握手完成后触发相对与服务端的upgrade事件
close socket关闭
error 错误消息
ws.send 发送消息,消息内容必须为字符串或buffer
let url = "ws://127.0.0.1:3000/socket?id="+id+"&name="+name+"&gid="+teamid;
let ws= new WebSocket(url);
ws.addEventListener("message",this.message.bind(this));
ws.addEventListener("open",this.open.bind(this));
ws.addEventListener("close",this.close.bind(this));
ws.addEventListener("error",this.error.bind(this));
ws.send("消息发送");
2、服务端接收调用
在服务端使用koa-websocket
其响应原理为客户端请求后,服务端切换响应为websocket,在upgrade事件中
1、收到客户端请求头
upgrade:websocket
connection:upgrade
Sec-WebSocket-Key:xxxx==
2、服务端使用258EAFA5-E914-47DA-95CA-C5AB0DC85B11通过sha1散列算法合并key手动修改Sec-WebSocket-Key 返回客户端完成
3、upgrade事件参数req,socket,upgradehead,socket.setNoDelay(true)
socket.write(修改过端返回头)
websocket = new WebSocfket()
websocket.setSocket(socket) 创建websocket链接
message响应客户端事件 ws.send() 发送客户端事件
let ws = ctx.websocket;
ws.on("message",this.EVNET_MESSAGE.bind(this));
ws.on("error",this.EVENT_ERROR.bind(this));
ws.on("close",this.EVENT_CLOSE.bind(this));
ws.on("timeout",this.EVENT_ERROR.bind(this));
3、在后期开发中加入了redis与mssql 来进行数据存储操作
因为redis自己有重连机制,不需要在处理重新连接,与sql数据库操作不同,不用重复端去调用初始化,此处为坑
this.client = redis.createClient({
host:host,port:port,
retry_strategy(options){
if (options.error.code === 'ECONNREFUSED') {
console.log('连接被拒绝');
Log.error('连接被拒绝');
}
if (options.times_connected > 10) {
console.log('重试连接超过十次');
Log.error('重试连接超过十次');
}
return Math.max(options.attempt * 100, 3000);
}
});
4、mssql
使用 new sql.ConnectionPool(this.config).connect();创建链接
在查询完成后sql.close();来关闭链接,跟api上说明使用pool.close()不同,pool会造成二次连接数据库失败。此处为坑
const sql = require('mssql');
class xx{
connect(){ //创建链接
return new sql.ConnectionPool(this.config).connect();
}
async query(str){ //查询数据
console.log("查询或入库")
let pool;
let result;
try{
pool = await this.connect()
result = await pool.request().query(str)
}catch(e){
console.log("数据库链接错误:"+e.message);
Log.error("数据库链接错误:"+e.message);
return Promise.reject(e.message).catch(str=>{
this.emit("DBError",str);
})
}
let rows = result.recordset;
let data=[]
if(result.recordsets.length){
data = result.recordsets[0];
}
sql.close();
return Promise.resolve(toJson(data))
}
}
网友评论