当前位置: 首页 > news >正文

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 就可以与服务端进行交互

相关文章:

  • Mysql 定时器
  • mysql 存储过程 遍历
  • mysql复制表结构的几种方式
  • TO_CHAR 和 TO_DATE的一些用法
  • Spark:学习笔记
  • linux:常用基本命令
  • Spark:数据倾斜处理一般从什么地方入手
  • MapReduce:中map和reduce的数量设置问题
  • MapReduce: 计数器(Counter)
  • Hive:HiveQL中如何排查数据倾斜问题
  • Java:字符序列:String,StringBuilder,StringBuffer三者的区别
  • Hive:分区和分桶
  • sql:Oracle:驱动表是什么?
  • MapReduce:原理之Word Count 以及Java实现
  • Hive:数据倾斜调优/解决方案总结
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • css布局,左右固定中间自适应实现
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • MySQL用户中的%到底包不包括localhost?
  • React的组件模式
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • vue.js框架原理浅析
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 关于Flux,Vuex,Redux的思考
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 用element的upload组件实现多图片上传和压缩
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (33)STM32——485实验笔记
  • (libusb) usb口自动刷新
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (剑指Offer)面试题34:丑数
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (一)80c52学习之旅-起始篇
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)Linux整合apache和tomcat构建Web服务器
  • .equals()到底是什么意思?
  • .libPaths()设置包加载目录
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .NET Core 成都线下面基会拉开序幕
  • .NET Reactor简单使用教程
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • @AliasFor注解
  • @Transient注解
  • [16/N]论得趣
  • [51nod1610]路径计数
  • [BUUCTF NewStarCTF 2023 公开赛道] week4 crypto/pwn