美文网首页前端Vue专辑
websocket学习总结-发送命令处理-接收数据处理(vue环

websocket学习总结-发送命令处理-接收数据处理(vue环

作者: 羽翼的翼 | 来源:发表于2019-10-15 21:44 被阅读0次

最近在用Vue和uniapp写websocket 中间遇到了好多问题
先说说在h5中发送socket

1.Vue写的h5页面中使用websocket

1.1封装命名为cysocket.js的文件 内容如下:

export function CySocket(config) {
  this.server = config ? config.server || '' : ''
  this.autoReconnect = config ? config.autoReconnect || '' : true
  var socket
  var times = 0// 尝试连接三次
  var interval
  var cySocket = this
  this.init = function(callback) {
    if (this.server === '') {
      console.error('服务器地址不能为空:)')
      return
    }
    if (interval) {
      clearInterval(interval)
      interval = null
      times = 0
    }
    try {
      if (socket && socket.readyState === 1) return
      socket = new WebSocket(this.server)
      socket.onopen = function(data) {
        if (config && config.openSocket) config.openSocket.call(cySocket, data)
      }
      socket.binaryType = 'arraybuffer'
      socket.onmessage = function(msg) {
        if (config && config.receiveMsg) config.receiveMsg.call(cySocket, msg.data)
      }
      interval = setInterval(function() {
        if (socket.readyState !== 1) {
          if (times > 2) {
            clearInterval(interval)
            interval = null
            times = 0
            console.log('无法连接到服务器...:)')
            return
          } else {
            console.log('通讯异常,正在尝试重连...:)')
            if (socket) {
              socket.close()
            }
            socket = new WebSocket(config.server)
          }
          times++
        } else {
          clearInterval(interval)
          interval = null
          times = 0
          console.log('已经连接到服务器')
        }
      }, 5000)
      if (typeof (callback) === 'function') callback.call(cySocket)
    } catch (e) {
      console.log(e.message)
      if (this.autoReconnect) {
        this.init(callback)
      }
    }
  }

  this.close = function() {
    if (interval) {
      clearInterval(interval)
      interval = null
      times = 0
    }
    if (socket && socket.readyState === 1) {
      socket.close()
    }
  }

  // 字符串转byte(防止中问传过去出现乱码的情况)
  function strToByte(str) {
    var bytes = new Array();  
    var len, c;  
    len = str.length;  
    for(var i = 0; i < len; i++) {  
        c = str.charCodeAt(i);  
        if(c >= 0x010000 && c <= 0x10FFFF) {  
            bytes.push(((c >> 18) & 0x07) | 0xF0);  
            bytes.push(((c >> 12) & 0x3F) | 0x80);  
            bytes.push(((c >> 6) & 0x3F) | 0x80);  
            bytes.push((c & 0x3F) | 0x80);  
        } else if(c >= 0x000800 && c <= 0x00FFFF) {  
            bytes.push(((c >> 12) & 0x0F) | 0xE0);  
            bytes.push(((c >> 6) & 0x3F) | 0x80);  
            bytes.push((c & 0x3F) | 0x80);  
        } else if(c >= 0x000080 && c <= 0x0007FF) {  
            bytes.push(((c >> 6) & 0x1F) | 0xC0);  
            bytes.push((c & 0x3F) | 0x80);  
        } else {  
            bytes.push(c & 0xFF);  
        }  
    }  
    return bytes; 
  }
  // 这里是对我们发送过去的代码进行处理
  this.sendMsg = function(data) {
    if (!socket || socket.readyState !== 1) {
      this.init(config)
    }
    var byte=[]
    byte = strToByte(data)
    var arrayBuffer = new ArrayBuffer(byte.length + 4)
    var dataView = new DataView(arrayBuffer)
    dataView.setInt32(0, byte.length, true) // 指定小端,主机字节序设置
    for (var i = 0; i < byte.length; i++) {
      dataView.setUint8(i + 4, byte[i])
    }
    if (socket && socket.readyState === 1) { socket.send(dataView.buffer) }
  }
  this.checkSocketState = function() {
    return socket.readyState
  }
}

1.2 在文件中引用

// 引入1.1中封装的文件
import { CySocket } from '../../../static/CySocket'

method中的方法如下

// 1.实例化socket 发送登陆心跳
    creatsocket() {
      const that = this
      Vue.prototype.cySocket = new CySocket({
        server: `ws://59.1.1.19:9128`, // 此为测试地址 用的时候需要写成后台提供的地址
        autoReconnect: false,
        openSocket: function() {
          // 2.obj为需要给后台传的参数
          const obj = {
            cmdCode: '0201',
            oppositeId: that.openid,
            timeToken: new Date().getTime()
          }
          const str = JSON.stringify(obj)
          // 3.根据要求通过this.sendMsg() 把需要上传的参数传递过去
          this.sendMsg(str)
        },
        // 监听socket的返回
        receiveMsg: function(data) {
         // data返回的数据类型看后台是如何返回的
         // 将收到的数据转换为字符串,这里是arraybuffer数据的转换
          that.ab2str(data, function(str) {
            var obj = JSON.parse(str)
            // 将收到的 数据保存在vuex中
            that.$store.commit('SET_RESULT_CODE', obj)
            Vue.prototype.code = that.$store.state.socket.resultCode
          })
        }
      })
      Vue.prototype.cySocket.init()
    },
    // arraybuffer转字符串
    ab2str(u, f) {
      var b = new Blob([u])
      var r = new FileReader()
      r.readAsText(b, 'utf-8')
      r.onload = function() {
        if (f)f.call(null, r.result)
      }
    },
    formatdate() {
      window.Date.prototype.format = window.Date.prototype.format || function(fmt) {
        var o = {
          'M+': this.getMonth() + 1, // 月份
          'd+': this.getDate(), // 日
          'h+': this.getHours(), // 小时
          'm+': this.getMinutes(), // 分
          's+': this.getSeconds(), // 秒
          'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
          'f': this.getMilliseconds() // 毫秒
        }
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
        for (var k in o) {
          if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
        }
        return fmt
      }
    },

1.3在其他页面中使用socket

注意: 1.2中的代码是在准备给socket发送登陆心跳的时候写的 写一次之后以后的界面就可以直接发送不需要在建立连接了

// 有车牌出场
    // 出场抬杆
    async raiseUp() {
      const raise = {
        cmdCode: '0206',
        gate_id: this.gate_id,
        oppositeId: this.openid,
        identity: this.parkNo,
        timeToken: new Date().getTime()
      }
      const raiseStr = JSON.stringify(raise)
     // 发送数据
      this.cySocket.sendMsg(raiseStr)
    // 对接收到的数据进行处理
      await this.status()
    },
    status() {
      // 根据自己业务需求写
      setTimeout(() => {
        const code = this.$store.state.socket.resultCode
        // console.log(code, 'rasiUp')
        if (code.resultCode === 1 && code.cmdCode === '0106') {
          // 需要把收到的参数传给支付界面渲染
          console.log(code, 'rasiUp')
          if (!this.ypcout) {
            this.ypcout = code
            this.carOutMsg = {}
            console.log(this.ypcout)
          } else {
            code.totalFee ? this.carOutMsg.TotalFee = code.totalFee : ''
          }
          this.pay = true
          this.success = false
          // code.totalFee ? this.carOutMsg['TotalFee'] = code.totalFee : ''
        } else if (code.cmdCode === '0106' && code.resultCode === 0) {
          this.trouble = this.fail = true
          return
        } else if (code.cmdCode === '0106') {
          this.trouble = this.fail = true
          return
        } else {
          this.fail = true
          this.answere = true
          return
        }
      }, 1000)
    }

1.4 项目中遇到的问题

遇到了两个问题:

    1. 发送时候中文乱码问题
      问题描述:发送socket的需求是 转换为Unicode编码
      转换的过程中遇到了中文 导致后台接收的时候中文乱码
      下图为协议文档说明:
      image.png
      解决方法: 见下方1.4.1
  • 2.接收时候ArrayBuffer 包含中文 转换的问题

1.4.1 发送时候中文乱码问题

在发送过去的代码中使用这个方法

 // 字符串转byte(防止中问传过去出现乱码的情况)
  function strToByte(str) {
    var bytes = new Array();  
    var len, c;  
    len = str.length;  
    for(var i = 0; i < len; i++) {  
        c = str.charCodeAt(i);  
        if(c >= 0x010000 && c <= 0x10FFFF) {  
            bytes.push(((c >> 18) & 0x07) | 0xF0);  
            bytes.push(((c >> 12) & 0x3F) | 0x80);  
            bytes.push(((c >> 6) & 0x3F) | 0x80);  
            bytes.push((c & 0x3F) | 0x80);  
        } else if(c >= 0x000800 && c <= 0x00FFFF) {  
            bytes.push(((c >> 12) & 0x0F) | 0xE0);  
            bytes.push(((c >> 6) & 0x3F) | 0x80);  
            bytes.push((c & 0x3F) | 0x80);  
        } else if(c >= 0x000080 && c <= 0x0007FF) {  
            bytes.push(((c >> 6) & 0x1F) | 0xC0);  
            bytes.push((c & 0x3F) | 0x80);  
        } else {  
            bytes.push(c & 0xFF);  
        }  
    }  
    return bytes; 
  }

使用

在上边定义的cysocket.js文件中的sendMsg函数中进行操作

  this.sendMsg = function(data) {
    if (!socket || socket.readyState !== 1) {
      this.init(config)
    }
    var byte=[]
    byte = strToByte(data)
    var arrayBuffer = new ArrayBuffer(byte.length + 4)
    var dataView = new DataView(arrayBuffer)
    dataView.setInt32(0, byte.length, true) // 指定小端,主机字节序设置
    for (var i = 0; i < byte.length; i++) {
      dataView.setUint8(i + 4, byte[i])
    }
    if (socket && socket.readyState === 1) { socket.send(dataView.buffer) }
  }

1.4.2 接收到ArrayBuffer转换的问题

先说说ArrayBuffer是什么?
ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 不能直接操作,而是要通过类型数组对象DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

我是如何操作的?

  • 具体用法可以参考1.2总的receiveMsg
    调用下方这个ab2str
  // arraybuffer转字符串
    ab2str(u, f) {
      var b = new Blob([u])
      var r = new FileReader()
      r.readAsText(b, 'utf-8')
      r.onload = function() {
        if (f)f.call(null, r.result)
      }
    },

用法

  // 监听socket的返回
        receiveMsg: function(data) {
         // data返回的数据类型看后台是如何返回的
         // 将收到的数据转换为字符串,这里是arraybuffer数据的转换
          that.ab2str(data, function(str) {
            var obj = JSON.parse(str)
            // 将收到的 数据保存在vuex中
            that.$store.commit('SET_RESULT_CODE', obj)
            Vue.prototype.code = that.$store.state.socket.resultCode
          })
        }

相关文章

网友评论

    本文标题:websocket学习总结-发送命令处理-接收数据处理(vue环

    本文链接:https://www.haomeiwen.com/subject/zleemctx.html