Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.0k views
in Technique[技术] by (71.8m points)

websocket连接失败后多久会触发error事件?

问题描述

websocket连接失败后多久会触发error事件?这个时间有没有方法可以设置

问题出现的环境背景

最近项目中用到了websocket,但是连接地址的端口不确定,因此前端需要从某个端口(例如ws://127.0.0.1:9000)开始累加去建立连接,然后通过onerror事件判断连接是否成功,但运行时发现从尝试连接到连接失败触发error事件的时间比较久,大概需要1s。这样如果枚举100次才连接成功,就需要占用100s的时间,效率太慢不可行。

function connectWebSocket(port = 9900) {
  return new Promise((resolve, reject) => {
    if (ws && ws.readyState === WebSocket.OPEN) {
      resolve(ws)
    } else {
      // 尝试建立连接
      console.log('connect', '-------', Date.now())
      ws = new WS(`ws://127.0.0.1:${port.toString()}`)
      ws.onopen = () => {
        // 连接成功
        console.log('open', '-------', Date.now())
        resolve(ws)
      }
      // 连接失败触发回调
      ws.onerror = () => {
        console.log('error', '-------', Date.now())
        reject()
      }
    }
  }).catch(() => {
    // 累加端口重建websocket
    if (port < 65534) {
      const newPort = port + 1
      return connectWebSocket(newPort)
    } else {
      ws.close()
      ws = null
      throw new Error('无法连接服务器')
    }
  })
}

image

尝试方法

运行发现open事件大概在建立连接20ms后触发,所以我试图通过setTimeout的方式来代替error事件,代码如下:

function connectWebSocket(port = 9900) {
  return new Promise((resolve, reject) => {
    // 加入isOpen变量来websocket是否握手成功
    let isOpen = false
    if (ws && ws.readyState === WebSocket.OPEN) {
      resolve(ws)
    } else {
      console.log('connect', '-------', Date.now())
      ws = new WS(`ws://127.0.0.1:${port.toString()}`)
      ws.onopen = () => {
        // 握手成功设置标识为true
        isOpen = true
        console.log('open', '-------', Date.now())
        resolve(ws)
      }
      // 需要确保定时器的回调在open事件之后执行
      setTimeout(() => {
        console.log(5, '-------', Date.now(), isOpen)
        if (!isOpen) {
          // 如果isOpen为false,说明没有握手成功,接着递归建立连接
          ws.close()
          reject()
        }
      }, 20)
      // ws.onerror = () => {
      //   console.log('error', '-------', Date.now())
      //   reject()
      // }
    }
  }).catch(() => {
    if (port < 65534) {
      const newPort = port + 1
      return connectWebSocket(newPort)
    } else {
      ws.close()
      ws = null
      throw new Error('无法连接服务器')
    }
  })
}

通过以上代码可以把判断是否需要重连的时间压缩到20ms左右,但问题在于我不确定open的触发时机能不能保证在20ms内(可能与电脑性能有关?)。
这种方式是否可行呢,或者定时器的时间设置为多少比较合适。


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

前端一个个端口扫描?天哪,我听到了网卡在哭泣。

前端不知道地址可以发一个请求先去问一下后端啊,后端自己起的 websocket 服务总归会知道自己用的是什么端口吧。为什么前端要闭着眼睛一个个试呢?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...