【问题标题】:How to reconnect socket after a passive network switch被动网络切换后如何重新连接套接字
【发布时间】:2021-12-16 04:52:07
【问题描述】:

所以我有一个 Swift 客户端、Node.js 服务器,并且正在使用 socket.io。我有一个问题,当用户在连接到服务器时从 WiFi 更改为 LTE(被动地,如果他们手动关闭 wifi 它工作正常),由于某种原因他们没有重新连接到服务器(只是遇到 ping 超时)。我尝试将 ping 超时增加到 50 秒,但没有任何效果。我的用户在连接到同一个房间时相互交互,所以这是一个大问题。

我在客户端的连接代码如下所示:

var socket: SocketIOClient?
fileprivate var manager: SocketManager?

func establishConnection(_ completion: (() -> Void)? = nil) {
    let socketUrlString: String = serverURL
    self.manager = SocketManager(socketURL: URL(string: socketUrlString)!, config: [.forceWebsockets(true), .log(false), .reconnects(true), .extraHeaders(["id": myDatabaseID])])
    self.socket = manager?.defaultSocket
    self.socket?.connect()
        //self.socket?.on events go here
}

在客户端,我的连接代码如下:

const io = require('socket.io')(http, {
  pingTimeout: 10000
});

io.on('connection', onConnection);

function onConnection(socket){
  let headerDatabaseID = socket.handshake.headers.id
  //in the for loop below, I essentially disconnect any socket that has the same database ID as the one that just connected (in this case, when a client is in a room with other clients, 
  //and then he/she switches from WiFi to LTE, the client reconnects to the socket server and this removes the old connection from the room it was in)
  for (let [id, connectedSocket] of io.sockets.sockets) {
    if (connectedSocket.databaseID == headerDatabaseID && socket.id != id) {
      connectedSocket.disconnect()
      break
    }
  }
//socket.on() events here
}

我的问题是——当客户端进行被动网络切换(WiFi -> LTE,反之亦然)时,我该如何重新连接客户端?我认为只需添加 .reconnects(true) 即可,但由于某种原因,它不是...

如果我可以更详细/有帮助,或者如果您想查看其他代码,请告诉我。

【问题讨论】:

    标签: javascript node.js swift sockets socket.io


    【解决方案1】:

    我相信解决您问题的方法可以简单也可以复杂;这取决于您的要求。我假设每个聊天室都有自己的 ID。

    如果您将该 ID 存储在设备的内存中,当用户重新连接时,您可以让套接字重新连接到您上次使用的房间 ID,然后他们将重新加入该房间。 这是不安全的。

    如果房间受到保​​护而不是公开的,如果有人知道/可以猜到房间 ID,则他们可能能够连接到不允许进入的房间。要解决这个问题,您需要实现某种身份验证或服务器端数据库来跟踪此类内容。

    【讨论】:

    • 我尝试将 roomID 存储在内存中,但遇到了一个难题。我计划存储一个“previousRoomID”。当套接字断开连接时,我需要设置这个变量,这样我就可以在不再访问房间 ID 之前访问它。问题是这样的:当网络发生变化时,socket 会立即断开连接,因此在 switch 语句的 .cellular 或 .wifi 情况下,房间 ID 已经无法访问。
    • @nickcoding2 我认为您可能需要将其存储为全局变量,而不仅仅是网络类型(蜂窝或 WiFi)范围内的一个变量。因此,如果您将变量设置在作用域的较高位置,然后从作用域的较低部分对其进行操作,即使它们的连接类型发生变化,您仍然可以访问它。
    • 我在后端修复了该问题的特定案例(手动)。现在,当网络开关是手动的(即用户关闭 wifi)时它可以工作,但是当开关是自动的(即用户从有 wifi 的区域走到没有 wifi 的区域)时,插座不会重新连接。有什么想法吗?
    • @nickcoding2 嗯...我认为这可能是您实施的 AnthonyR/Reachability 解决方案的错误。至少这是我怀疑的......
    • 看,我认为这主要是他的 socket.io 实例的实现问题——虽然,关于连接的命名空间,它应该是他的 api 生成的身份验证令牌/cookie服务器并存储在他的客户端上。当然对于 dev 来说,他现在可以只使用 db id。
    【解决方案2】:

    考虑到行为因手动或被动切换而异,听起来问题出在 iOS 客户端上。我注意到您正在使用套接字 - 它似乎是某种自定义套接字包,对吗?有使用这个的理由吗? URLSession 是一个更高级别的实现,它管理诸如切换之类的事情。

    Apple 开发了一种称为 Wifi 辅助的东西来管理切换。它是操作系统的一部分,并在内部进行管理。根据苹果的说法:“使用 URLSession 和网络框架已经为我们带来了新的 WiFi 辅助优势。”。它于 2015 年 9 月在 iOS 9 中发布。 但是,如果您使用的是其他类型的套接字,无论这个“socketIOClient”是什么——尤其是 2015 年 9 月之前开发的软件包,您可能正在绕过 Wifi 辅助。我看到的最新版本的 SocketIO 客户端是在 2015 年编写的,当 iOS 9 发布时,对这个包的支持似乎已经停止。

    当用户手动更改连接时,这会手动提示操作系统断开并重新建立连接,而被动权衡通常依赖此 Wifi Assist。

    当您检测到发生被动切换时,您可以尝试以编程方式断开并重新建立连接,但我不建议这样做...对于初学者来说,它会使您的代码更加混乱。它可能会降低用户体验。但更糟糕的是,这可能不是您在使用这个过时的 socketIO 包时遇到的唯一问题。真的不知道你会遇到什么样的维护问题。最好只重构代码以使用 iOS 提供的最新网络机制。

    【讨论】:

      【解决方案3】:

      如果.reconnects(true) 不起作用,您可以尝试手动解决 Apple 的可达性问题。 This 可能会更容易——它是“用闭包用 Swift 重写”的可达性功能。

      在你的情况下,你可以这样使用它:

      let reachability = try! Reachability()
      
      reachability.whenReachable = { reachability in
          if reachability.connection == .wifi {
              print("Reachable via WiFi")
              self.socket.disconnect();
              establishConnection() //this is your method defined in the question
          } else {
              print("Reachable via Cellular")
              self.socket.disconnect();
              establishConnection() //this is your method defined in the question
          }
      }
      reachability.whenUnreachable = { _ in
          print("Not reachable")
      }
      
      do {
          try reachability.startNotifier()
      } catch {
          print("Unable to start notifier")
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-17
        • 2015-09-16
        • 1970-01-01
        • 2012-03-27
        • 1970-01-01
        • 2014-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多