keyword:websocket回调,websocket像ajax一样,websocket接口请求,同步回调,websocket MVC框架

前言

传统http短连接拉取接收数据太浪费资源,tcp每次都得建立连接,三次握手,释放,只能单向通信,定时轮询。
而websocket可以建立长连接,后一直保持,节约服务器资源,跟每台客户机只维持一个连接就行。
节省流量 不需要频繁地发起关闭tcp连接,可以双向通信,
协议以及数据格式自己算了算,浏览器、app、物联网多种设备一套接口通用,省略HTTP上不多余的信息,

基于以上原因,开发一套socket框架来代替http ajax模式,同时保持跟http一样容易上手

目的

用websocket实现Ajax回调效果,所有接口请求用websocket进行,
想要使websocket发送的消息实现跟ajax回调消息那种效果,发送出去,然后回调函数里收到服务器发送来的消息

难点

websocket与http不同的之处在于,http发的请求是同步的,浏览器发起请求会同步等待服务器返回,而socket是发送完了就结束了,不管服务器又没返回,而且先发地数据不一定先收到,不按顺序返回,
难点就在于发送数据在ws.send函数里,而接收数据在ws.onmessage里,数据不能互通

原理

解决方法
发送消息的时候把回调函数存到一个数组中,数组下标用唯一键名避免冲突,键名要发送给服务器,服务器返回数据的时候要带上,
收到服务器消息时,取出键名去调用数组中对应的回调函数,把数据传入回调函数执行回调操作
这样就实现了跟ajax一样的效果

实现

代码示例
socket.js

//websocket地址
let host = "ws://localhost:8282";
let ws = null;
let socketOpen = false;
let callbackArr = [];
let msgArr = [];
//心跳时间
let heartCheckTime = 45000;
//重连尝试次数
let reconnectTime = 0;

function wsConnect() {
      
        


    ws = new WebSocket(host);

    // 打开socket连接
    ws.onopen = e => {
      
        
        socketOpen = true;
        console.log('连接成功');

        //待发送消息队列
        if (msgArr.length) {
      
        
            for (let i in msgArr) {
      
        
                sendMsg(msgArr[i].data, msgArr[i].callback)
            }
            msgArr = []
        }
        // 心跳
        heartCheck()
    };


    // socketClose
    ws.onclose = e => {
      
        
        console.log('连接已断开', e);
        socketOpen = false;
        reconnect();
    };


    //连接发生错误
    ws.onerror = e => {
      
        
        console.log('连接发生错误', e);
        socketOpen = true;
        reconnect();
    };


    //接收消息
    ws.onmessage = e => {
      
        
        // 按api保存回调
        let callBackData = JSON.parse(e.data);
        let key = callBackData.key;
        if (!key) return;
        callbackArr[key](callBackData)

    }
}


// 发送消息
function send(data, callback) {
      
        
    callbackArr[data.key] = callback
    if (socketOpen) {
      
        
        ws.send(JSON.stringify(data))
    } else {
      
        
        // 未开启,加入队列
        msgArr.push({
      
        data, callback});
        wsConnect();
    }
}


// 心跳检测
function heartCheck() {
      
        
    if (socketOpen) {
      
        
        setInterval(() => {
      
        
            ws.send('ping')
            console.log("发送ping", heartCheckTime)
        }, heartCheckTime);
    }
}


// 重连
function reconnect() {
      
        
    if (!socketOpen && reconnectTime <= 10) {
      
        
        setTimeout(() => {
      
        
            wsConnect()
            reconnectTime++
            console.log('重新连接', reconnectTime)
        }, 2000)
    }
}

module.exports.send = send

调用

const socket = require('./socket.js');
 socket.send({
      
        
                api: 'login',
                app: 'ios',
                key: 'callback'+new Date().getTime()+Math.round(Math.random()*10),
                data: {
      
        name: 'admin',password:'123456'}
            }, res => {
      
        
                if (res.code == 0) {
      
        
                    console.log(res)
                }
            })

具体字段跟协议根据实际情况设计,我后端用的是php,基于workerman跟thinkOrm封装的一套框架,基本用法跟thinkphp一致,现在全部接口都用websocket,如需参考请移步
https://github.com/feixuekeji/flysocket

flysocket

flysocket是一款基于GatewayWorker开发的的支持双向通信长连接websocketMVC开发框架,适用于前后端通过长连接进行通讯的web项目,游戏服务器,同时也适用于开发tcp长连接应用如即时通信、物联网、消息推送、智能家居等。

开发初衷是为了实现客户端(包括浏览器web,APP,小程序,物联网设备)与服务端通信使用统一的socket长连接接口,开发一套接口用于多种客户端,服务器与客户端保持长连接,解决传统http模式每次连接都要初始化浪费系统资源的问题。

框架是一个通过websocket协议的MVC框架,前后端数据以json格式传输,框架多处参考thinkPHP,用法也尽量保持了跟tp方法一致,跟传统http项目一样容易上手。