簡體   English   中英

是否可以在 Socket.IO 中進行服務器端回調

[英]Is it possible to do a server-side callback within Socket.IO

有這個問題(和評論)問了我的確切問題,但從來沒有得到體面的回答。 我找不到其他任何地方可以幫助我解決這個非常煩人的問題。

我有這個產品,它位於連接到他們網絡的用戶家中。 當他們在他們的網絡之外時,我希望他們能夠在世界任何地方通過互聯網連接安全地訪問所述產品。 當我的應用需要數據(僅存儲在家里的產品上)時,它會執行以下步驟:

  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

有沒有辦法解決這個問題,我覺得不支持服務器端回調很愚蠢,或者我只是做錯了什么?

問題是,多個不同的產品將同時連接到該服務器,因此回調是唯一合乎邏輯的方式將數據發送到正確的位置。 我已經看到人們制作自己的回調的解決方案,但我需要它,以便可以在一個 go 中執行和發送此代碼的多個實例,而不是在不同的發出函數中分解它。

經過數小時的頭撞桌子后,我找到了一個使用 Socket.io 進行服務器端調用的小而有效的解決方案!

我會盡可能詳細地說明這一點,因為我在互聯網上看到過同樣的問題......

因此,對於那些(像我一樣)將有多個客戶端連接到同一服務器的人,並且您希望使用回調將數據從客戶端以一種可管理的方式發送回服務器,而無需使用回調,因為我們無法使用它們。 或者對於那些想要在直接與特定 sockets 交談時具有回調功能的人:

例如,我的應用程序向我的服務器發出請求,詢問保存在其他地方的數據(在我的情況下,我的應用程序正在詢問有關他們家中樹莓派上保存的一些燈的數據,因此他們可以在任何地方訪問該數據是)。

我的應用程序調用我的 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 客戶端(位於我的用戶家中)用於此相關的 function:

    @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)

分解這段代碼......(頂部的兩個常量bridgeIDFromAppsocketID只是我存儲在服務器上的兩個常量,因此服務器知道將數據發送到哪里)

  1. 該應用程序調用 API 並通過套接字向持有數據的客戶端發送一條消息:

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

  2. 我的 python 客戶端接收命令,通過 localIP 獲取所述數據,將其粘貼在附加了 socketID 的 JSONObject 中,因此我們知道當數據返回服務器並將其發送回服務器時將其發送到何處:

    sio.emit('lightDataCallback',output)

  3. 這是它發揮創意的地方,因為我們不能進行回調,所以我在 function 中創建了一個偵聽器,其中首先使用套接字 object 連接用戶。 這是因為它將接收來自所有客戶端的所有發射到lightDataCallback發射 function。 所以在套接字 object function 我有這個代碼來檢索所述數據:

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

    然后我們調用 function ,它最初是在我們的應用程序從這個發射器調用的第一個端點內實例化的:

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

現在,我們可以使用簡單的res.send(data)將數據發送回客戶端。 但是,如果連接了數千個客戶端,並且很多人運行相同的 function,那么您將遇到數據發送給錯誤的人的問題,因為無法判斷功能和數據是否正確按順序返回(也許他們家的客戶樹莓派檢索數據很慢)。

為了確保發送給正確的人,我有一個簡單的 if 語句來檢查返回給 function 的數據是否真的是給這個人的。 它檢查數據中的 socketID 是否與執行請求的當前 socketID 相同,如果不是,則不做任何事情,直到再次調用此 function 並再次檢查。 如果是,那么我們可以放心地假設返回給我們的 function 的數據將發送給正確的人,因此我們可以發送數據:

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

(我返回給服務器的數據里面是socketID,看第2步。它是我們用來標記數據的所有者)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM