【问题标题】:Is it possible to do a server-side callback within Socket.IO是否可以在 Socket.IO 中进行服务器端回调
【发布时间】:2020-07-16 12:19:09
【问题描述】:

有一个question (and comment) 提出了我的确切问题,但从未得到体面的回答。我找不到其他任何地方可以帮助我解决这个非常烦人的问题。

我有这个产品,它位于连接到他们网络的用户家中。当他们在他们的网络之外时,我希望他们能够在世界任何地方通过互联网连接安全地访问所述产品。当我的应用需要数据(仅存储在家里的产品上)时,它会执行以下步骤:

  1. 应用程序向服务器发送请求,要求其在家中的产品中获取数据
  2. 服务器获取请求并通过 socket.io 向其产品发送消息
  3. 产品接收请求并获取数据(存储在本地)并将其返回给服务器(回调)
  4. 服务器接收到回调发送的数据,返回给用户App。

现在我知道使用 socket.io 你可以在客户端进行回调,但为什么不能在服务器端回调呢?

目前,使用我现在拥有的代码,我收到错误 Callbacks are not supported when broadcasting:

服务器端代码(Nodejs):

app.get('/hueapi/lights', verifyToken, (req,res) => {
  const bridgeIDFromApp = req.header('bridgeID');
  const socketID = socketRefDic[bridgeIDFromApp]['socketID'];
  io.to(socketID).emit('getAllLights', function(data){
      res.send(data); // The callback function that shows the data given by the python client
  });
});

客户端代码(python):

def getAllLights(data):
    lightData = requests.get('http://localhost:4000/lights/')
    return lightData

有没有办法解决这个问题,我觉得不支持服务器端回调很愚蠢,还是我做错了什么?

问题是,多个不同的产品将同时连接到该服务器,因此回调是唯一合乎逻辑的方式将数据发送到正确的位置。我见过人们制作自己的回调的解决方案,但我需要它,以便可以一次性执行和发送此代码的多个实例,而不是在不同的发出函数中分解它。

【问题讨论】:

    标签: javascript python node.js python-3.x socket.io


    【解决方案1】:

    在我的头撞在桌子上几个小时后,我找到了一个使用 Socket.io 进行服务器端调用的小而有效的解决方案!

    我会尽可能详细地说明这一点,因为我在互联网上看到过同样的问题......

    因此,对于那些(像我一样)将有多个客户端连接到同一服务器的人,并且您希望使用回调将数据从客户端以一种易于管理的方式发送回服务器,而无需使用回调,因为我们不能使用它们。或者对于那些希望在直接与特定套接字对话时具有回调功能的人:

    例如,我的应用程序向我的服务器发出请求,请求获取保存在其他地方的数据(在我的情况下,我的应用程序正在请求关于保存在他们家中树莓派上的一些灯的数据,以便他们可以访问数据,无论它们在哪里)。

    我的应用调用我的 Cloud API (Nodejs) 的这个端点:

    app.get('/hueapi/lights', verifyToken, (req,res) => {
      const bridgeIDFromApp = req.header('bridgeID');
      const socketID = socketRefDic[bridgeIDFromApp]['socketID'];
      io.to(socketID).emit('getAllLights', 'getAllLights')
      lightDataCallbackFunction = function(data){
        console.log(Object.keys(data))
        if(Object.keys(data) == socketID){
          res.send(data);
        }
      }
    });
    

    还有我的 python 客户端(位于我的用户家中)用于此相关功能:

        @sio.event
        def getAllLights(data):
                lightData = requests.get('http://192.168.0.55:5000/lights').json()
                output = {sio.eio.sid: lightData};
                sio.emit('lightDataCallback',output)
    

    分解这段代码......(顶部的两个常量bridgeIDFromApp 和socketID 只是我存储在服务器上的两个常量,因此服务器知道将数据发送到哪里)

    1. 应用调用 API 并通过套接字向持有数据的客户端发送消息:

      io.to(socketID).emit('getAllLights', 'getAllLights')

    2. 我的 python 客户端接收命令,通过 localIP 获取所述数据,将其粘贴到附加了 socketID 的 JSONObject 中,这样我们就知道当数据返回服务器并将其发送回服务器时将数据发送到哪里:

      sio.emit('lightDataCallback',output)

    3. 这是它发挥创意的地方,因为我们不能进行回调,所以我在函数中创建了一个侦听器,其中套接字对象首先用于连接用户。这是因为它将接收来自所有客户端的所有发射到lightDataCallback发射函数。所以在套接字对象函数中,我有这段代码来检索所述数据:

      socket.on('lightDataCallback', (socket) => {
        lightDataCallbackFunction(socket);
      });
      

      然后我们调用最初在第一个端点内实例化的函数 我们的应用程序从这个发射器调用的:

      lightDataCallbackFunction = function(data){
      console.log(Object.keys(data))
      if(Object.keys(data) == socketID){
            res.send(data);
        }
      }
      

    现在,我们可以使用简单的res.send(data) 将数据发送回客户端。但是,如果连接了数千个客户端,并且很多人运行相同的功能,那么您将遇到数据被发送给错误的人的问题,因为无法判断功能和数据是否正确按顺序返回(可能他们家的客户端树莓派检索数据很慢)。

    为了确保发送给正确的人,我有一个简单的 if 语句来检查返回给函数的数据是否真的是给这个人的。它检查数据中的 socketID 是否与执行请求的当前 socketID 相同,如果不是,则在再次调用此函数并再次检查之前不做任何事情。如果是,那么我们可以安全地假设返回给我们函数的数据将发送给正确的人,因此我们可以发送数据:

    if(Object.keys(data) == socketID){
      res.send(data);
    }
    

    (我返回给服务器的数据里面是socketID,看第2步,就是我们用来标记数据的主人)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-30
      • 1970-01-01
      • 2017-04-27
      • 2013-03-14
      • 1970-01-01
      • 1970-01-01
      • 2016-09-21
      • 2022-08-08
      相关资源
      最近更新 更多