node.js websocket.io 搭建 websocket 通信服务
有一段时间没有写博客了,前段时间一直在忙项目,由于项目的需求,需要搭建一个websocket的通信服务,用于教师机对客户端(学生端)进行通信已执行一些操作,之前用java写了一个websocket通信的东西,但是这个东西的稳定性太差,本来是搞java的,说是撸一个netty框架的websocket,但是项目组长说用node.js写一个,,,
websocket.io W3Cschool api 文档
https://www.w3cschool.cn/socket/socket-odxe2egl.html
废话不多少,直接上代码,代码运行需要安装 node环境 和相关模块
服务端:
let express = require('express');
let http = require('http');
let request = require("request");
let qs = require('querystring');
let app = express()
app.use(express.static(__dirname))
app.get('/', function (res, req) {
res.header('Content-Type', 'text/html;charset=utf8')
res.sendFile(path.resolve('index.html'))
})
let server = http.createServer(app)
let teacher = {};
// 客户端实例id
let users = {};
let userType = {};
let post_data = {};
let resData = {};
let url = "";
// 因为websocket协议是要依赖http协议实现握手的,所以需要把httpServer的实例传递给socket.io
let socketIo = require('socket.io')
let io = socketIo(server)
// 在服务器监听客户端的链接
io.on('connection', socket => {
console.log('客户端连接到服务器')
io.to(socket.id).emit('message',"服务器连接成功......");
console.log(users)
console.log(teacher)
// 监听接受客户端发过来的消息
socket.on('message', msg => {
console.log('客户端消息 :', msg)
let data = msg;
let key = getTeacherAccId(socket.id);
if (data && data.code && key) {
resData = {};
post_data = {};
url = "";
switch(data.code){
case 2001: // 延长考试时间
// 设置参数
post_data.examId = data.data.examId;
url = "http://xx.xx.xx:8006/xxx";
postRequest(url,data.data.token,post_data,resData,false,key);
break;
case 2002: // 强制交卷
post_data.examId = data.data.examId;
post_data.accId = data.data.accId;
resData.code = data.code;
resData.message = "强制交卷";
resData.data = post_data;
url = "http://xx.xx.xx:8006/xxx";
postRequest(url,data.data.token,post_data,resData,false,key);
break;
case 2003: // 关闭考试
post_data.examId = data.data.examId;
post_data.flag = 1;
resData.code = data.code;
resData.message = "关闭考试";
resData.data = post_data;
url = "http://xx.xx.xx:8006/xxx";
postRequest(url,data.data.token,post_data,resData,true,key);
break;
default:
resData.code = data.code;
resData.message = "未知操作";
resData.data = {};
io.to(socket.id).emit('message',resData);
}
}else{
resData.code = 1;
resData.message = "未知操作";
resData.data = {};
io.to(socket.id).emit('message',resData);
}
})
socket.on('error', () => {
console.log('连接错误')
})
socket.on('leave', function () {
socket.emit('disconnect');
});
//监听与客户端断开连接事件
socket.on('disconnect',function(){
let value = socket.id;
for(var i in teacher) {
if (teacher[i] == value) {
delete teacher[i];
}
}
for(var room in users) {
for (var r in users[room]) {
for (var acc in users[room][r]) {
if (users[room][r][acc] == value) {
users[room].splice(r,1);;
}
}
if (users[room].length == 0) {
delete users[room]
}
}
}
});
});
// 中间件
io.use((socket, next) => {
var accId = socket.handshake.query.accId?socket.handshake.query.accId:"";
var examId = socket.handshake.query.examId?socket.handshake.query.examId:"";
var sysFlag = socket.handshake.query.sysFlag?socket.handshake.query.sysFlag:-1;
if (sysFlag.length>0 && sysFlag == 0 && accId.length>0) {
teacher[accId] = socket.id;
next();
}else if (sysFlag.length>0 && sysFlag == 1 && accId.length>0 && examId.length>0 ){
if (users[examId] === undefined || users[examId].length == 0) {
users[examId] = [];
}
//加入分组 ,根据连接区分是教师端还是客户端
socket.join(examId,function(){
var data = {};
data[accId] = socket.id;
users[examId].push(data);
});
next();
}else{
next(new Error('参数缺失'));
}
});
function getTeacherAccId(value){
for(var i in teacher) {
if (teacher[i] == value) {
return i;
}
}
}
/**
* url 请求地址
* token token
* post_data 请求参数
* data 响应前端数据
* 是否针对全部客户端
*
*/
function postRequest(url,token,post_data,data,flag,key){
var content = qs.stringify(post_data);
var options = {
url: url,
async: false,
form: content,
method: 'post'
};
request.post(options, function(error, response, body) {
body = JSON.parse(body)
if (body && body.code == 0) {
if (!flag) {
var saccId = post_data.accId;
var examId = post_data.examId;
var socketId = getUserAccId(examId,saccId)
if (socketId.length >0) {
io.to(socketId).emit('message',data);
}else{
io.to(teacher[key]).emit('message',{"code":1,"message":"学生端未连接","data":{});
return ;
}
}else{
socketIO.to(examId).emit('message',data);
}
io.to(teacher[key]).emit('message',{"code":0,"message":"操作成功","data":{});
}else{
io.to(teacher[key]).emit('message',body);
}
});
}
function getUserAccId(key,value){
var objArr = users['"'+key+'"'];
if (objArr) {
for (var r in objArr) {
for(var j in objArr[r]){
var data = objArr[r]['"'+value+'"']
return data;
}
}
}
return '';
}
// 监听3001端口
server.listen(3001)
教师:
<!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>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:3001?accId=00000112&sysFlag=0');
window.onload = function(){
//监听与服务器端的连接成功事件
/**
* socket.emit('leave');
*/
socket.on('connect',function(){
console.log('连接服务器成功');
var data = {'code':2002,
'data':{
'examId':'c8974fcf-4502-4ef8-8a29-280c864a85gg',
'accId':'0000011', // 学生账号
}
}
// 执行相关操作
socket.send(data);
});
//客户端收到服务器发过来的消息后触发
socket.on('message',function(message){
console.log(message);
});
//监听与服务器端断开连接事件
socket.on('disconnect',function(){
});
};
</script>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
学生端:
<!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>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://192.168.2.58:3001?accId=adasfgghs112&sysFlag=1&examId=c8974fcf-4502-4ef8-8a29-280c864a85gg');
window.onload = function(){
//监听与服务器端的连接成功事件
/**
* socket.emit('leave');
*/
socket.on('connect',function(){
console.log('连接服务器成功');
});
//客户端收到服务器发过来的消息后触发
socket.on('message',function(message){
console.log(message);
});
//监听与服务器端断开连接事件
socket.on('disconnect',function(){
});
};
</script>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
使用 node index.js 启动,打开浏览器访问 localhost:3001 就可以与服务端进行交互