最近在研究 websocket ,之前也在其它的项目中遇到过它,但当时没有那么在意它,而通过这几天对它深入研究就发现其有一颗十分“心”,它是解决 IM(即时通讯)的需求的一种途径,它能让我们明白现在主流市场上的 IM (即时通讯)工具(如:QQ、微信等)是通过什么技术来实现。
websocket 还有一个与它相似的叫 socket.io,那么它们有什么区别点下面的链接去阅读
https://zhuanlan.zhihu.com/p/346650330
本文将记录如何建立服务端,因这一部分比较难,容易入坑,而客户端的架设相对而言比较简单,网络上也基本就有。
一、基本的服务端建立
var ws = require("nodejs-websocket");
const uuid = require('node-uuid');
const log = require('./log');
const redis = require('./redisHelper');
let cacheKey_conn = '', cacheKey_user, cache_expire_36 = 3600;
let result = (Inquiry, data) => {
let params = {Inquiry};
if (data) {
params = Object.assign(data, params);
}
return JSON.stringify(params);
},
user = [],
boardcast = function (key, params) {
log.info("BOAR:" + cacheKey_user);
log.info("S----------------");
log.info("To conn Key:" + key);
user.forEach(function (item) {
if (item.key === key) {
item.sendText(params);
}
})
log.info("E------------------");
log.info('user size', user.length);
server.connections.forEach(function (conn) {
// .forEach 是调用数组里每个元素 //
var item = conn.frameBuffer;
log.info(server.connections.length);
//if(conn.frameBuffer.name==null){
//conn.sendText(str)
//}
});
},
cacheKey = {
conn: 'conn:',
online: 'online:',
guest: 'guest:'
},
cacheData = {
conn: (conn, params) => {
console.log('conn keys', user.length);
let exists = false;
user.forEach(function (item) {
if (item.hasOwnProperty('key')) {
if (item.key === conn.key) {
exists = true;
}
}
});
cacheKey_conn = cacheKey.conn;
if (params.hasOwnProperty('UUID')) {
// 访客上线
cacheKey_conn += cacheKey.guest;
}
cacheKey_conn += conn.key;
log.info('conn exists:', exists);
if (exists === false) {
user.push(conn);
}
},
pingConn: (conn_key, cache_key, fn) => {
let is_exists = false;
user.forEach(function (item, index) {
if (item.hasOwnProperty('key')) {
if (item.key === conn_key) {
is_exists = true;
}
}
});
if (is_exists === false) {
// 不在线
}
fn(is_exists);
},
unConn: (conn) => {
user.forEach(function (item, index) {
if (item.hasOwnProperty('key')) {
if (item.key === conn.key) {
user.splice(index, 1);
}
}
});
}
};
console.log("开始建立连接...")
var server = ws.createServer(function (conn) {
conn.on("text", function (str) {
log.info("收到的信息为:" + str);
let params = JSON.parse(str);
cacheKey_user = cacheKey.guest + cacheKey.online + params.UUID;
if (params.hasOwnProperty('action')) {
switch (params.action) {
case 'online':
conn.sendText(result('online', {key: conn.key}));
break;
}
}
})
conn.on("close", function (code, reason) {
log.info("关闭连接");
cacheData.unConn(conn);
});
conn.on("error", function (code, reason) {
log.error("异常关闭");
cacheData.unConn(conn);
});
}).listen(8001);
console.log("WebSocket建立完毕");
二、带 SSL 协议的服务端
1、 mkcert 的自签证书
网络上的方法有很多,如通过 openSSL 来创建 cert 证书,这种方法都是复制性较多。后来发现了 mkcert 这个家伙是相当的吸引眼球于是拿过来用了。
const mkcert = require('mkcert');
var ws = require("nodejs-websocket");
const Https = require('https');
// const uuid = require('node-uuid');
const log = require('./log');
const redis = require('./redisHelper');
console.log("开始建立连接...")
// create a certificate authority
mkcert.createCA({
organization: 'Hello CA',
countryCode: 'NP',
state: 'Bagmati',
locality: 'Kathmandu',
validityDays: 365
}).then(ca => {
// then create a tls certificate
mkcert.createCert({
domains: ['127.0.0.1', 'localhost'],
validityDays: 365,
caKey: ca.key,
caCert: ca.cert
}).then(cert => {
// 向server传递key和cert参数
const app = Https.createServer({
key: cert.key,
cert: cert.cert
}).listen(8001);
// 实例化WebSocket服务器
const wss = ws.createServer({
server: app
});
// 如果有WebSocket请求接入,wss对象可以响应connection事件来处理
wss.on('connection', (conn) => {
console.log('服务器已启动,监听中~');
conn.on("text", function (str) {
log.info("收到的信息为:" + str);
let params = JSON.parse(str);
})
conn.on("close", function (code, reason) {
log.info("关闭连接");
});
conn.on("error", function (code, reason) {
log.error("异常关闭");
});
});
console.log("WebSocket建立完毕");
});
});
MPN mkc
https://www.npmjs.com/package/mkcert
使用了 mkcert 的证书后,还是产生了以下的问题
Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
搜索之后发现这个问题的原因是
- WebSocket地址不能使用IP,必须使用域名。因为证书是针对域名来进行配置的。
- 证书必须符合新Chrome规范,否则会出现NET::ERR_CERT_COMMON_NAME_INVALID错误,具体详情见Chrome帮助。如果重新签署后还是出现此问题,需要按下证书中的DNS地址是否包含使用的域名。
- 如果是开发环境的自签证书,需要配置到本地证书库中,否则会出现NET::ERR_CERT_AUTHORITY_INVALID错误。
2、找个域名去 SSL 服务商那申请
用 nginx 的证书就可以了
// 需安装ws模块 npm install ws
let WebSocketServer = require('ws').Server;
let https = require("https");
let fs = require("fs");
let server = https.createServer({
cert: fs.readFileSync('./cert/ca.key').toString(),
key: fs.readFileSync('./cert/ca.pem').toString()
}, (req, res) => {
res.writeHead(200);
res.end("this is a websocket server \n");
}).listen(8001);
let wss = new WebSocketServer({ server: server });
wss.on(
"connection",
connection => {
console.log("has user to connected");
}
);
NodeJS WS 的 GitHub 分享
https://github.com/websockets/ws
转载请注明:隨習筆記 » 利用 webSocket 建立客服系统(服务端篇)