2017-06-20 96 views
0

所以我在寫一個的NodeJS應用程序,並作序,我的問題,請理解我的設置目前是如何工作的:Socket.IO的Emit被髮射到所有客戶端

我有誰通過Socket.io連接的客戶端「服務器X「,然後我的」服務器X「通過Socket.io連接到」服務器Y「,它們都通過Socket.io將數據發回給對方。

客戶< --->服務器X < --->服務器Ÿ

客戶端是指用戶和他們的瀏覽器,然後我有我的服務器X和我的服務器Y都運行的節點的應用程序。

因此,在我的服務器X下面的代碼中,如果你看看第4行,它的工作原理與它應該完全一樣。它僅將消息發送給請求它的客戶端。

io.on('connection', function(socket){ 

    // This works just fine. 
    socket.emit('return_login', 'Test Message'); 

    socket.on('login', function(data){ 
     // This line correctly sends the data to Server Y 
     server_y.emit('login', data); 
    }); 

    server_y.on('return_login', function(data){ 
     // This emits to all connected clients??? 
     socket.emit('return_login', data); 
    }); 

}); 

現在我的問題是,當「服務器Y」發出return_login到服務器X,我希望發生什麼是服務器X採取通過服務器Ÿ發出的價值,只是其發回給原來的客戶端,或網頁瀏覽器。但出於某種原因,該線路發射給所有連接的客戶端。

我有一臺筆記本電腦,這臺電腦和我的手機都在測試這個,每次發生這種情況都會發送給所有人。

如果有人可以請幫助我,我將不勝感激。如果我需要發佈更多的代碼,請讓我知道。

回答

0

因爲你已經安裝了一個單獨的偵聽器的每個插座用於return_login消息據發送到所有客戶端我的解決方案。因此,當一個客戶端登錄並將return_login消息發送回您的服務器時,對於每個查看該消息並將其轉發給該套接字的套接字,您都有一個單獨的偵聽器。通過這種方式,它被髮送到每個連接的套接字。

解決該問題的一種方法是確保return_login消息僅發送到它所屬的套接字。如果您可以發送帶有該消息的socket.id,並讓該服務器將該ID作爲響應的一部分回顯,那麼您可以檢查收到該消息的時間,以確保只將其發送到它所屬的套接字。

這是純粹的基於消息的系統的問題之一。您正嘗試在請求者看到響應的地方執行請求/響應,但socket.io不是請求/響應系統。將響應發送給該特定消息的所有偵聽器,並且由於您爲每個連接的單個套接字都有一個該消息的偵聽器,因此每個套接字都會看到它,然後將其轉發給它的客戶端。

因此,具有相應的修改到其他服務器,以回顯id值,你可以這樣做:

io.on('connection', function(socket){ 

    // This works just fine. 
    socket.emit('return_login', 'Test Message'); 

    socket.on('login', function(data){ 
     // add our id so we can identify our response back 
     data.id = socket.id; 
     server_y.emit('login', data); 
    }); 

    let fn = function(data) { 
     // check to see if this message is destined for this socket 
     if (data.id === socket.id) { 
      // make data copy with id value removed so 
      // we don't send that to the client 
      let tempData = Object.assign({}, data); 
      tempData.delete(id); 
      socket.emit('return_login', tempData); 
      // we're done with this listener so remove it 
      server_y.removeListener('return_login', fn); 
     } 
    }); 

    server_y.on('return_login', fn); 

}); 

這可能是很有誘惑力的只是刪除您的偵聽器後return_login消息您會收到它,但是如果兩個客戶端同時登錄並因此同時擁有監聽器,則會導致競爭狀況,然後第一條消息將被兩個監聽器接收。

+0

你解決了我的問題,但我仍然困惑。爲什麼要從該tempData對象中刪除套接字ID?你說在評論中刪除ID值的數據副本,所以我們不會發送到客戶端,但你不想知道他們是什麼套接字ID?另外,我刪除了'server_y.removeListener('return_login',fn)''這一行,因爲它使得它只能嘗試一次登錄。 – flakeyjake

+0

@flakeyjake - 客戶端不需要知道服務器端連接的'socket.id',所以我想我會刪除它以保持與之前發送給客戶端的數據結構相同。我沒有理由想把它發送給客戶。如果您想避免將其移除,您可以允許將其發送給客戶端 - 無損。我不知道你想要多次登錄。是的,要做到這一點,您要麼在發送登錄信息時建立新的聽衆,要麼不要刪除它。 – jfriend00

+0

@flakeyjake - 由於您看起來可能是新手,如果我的答案爲您提供瞭解決方案,那麼您可以通過單擊答案左側的綠色複選標記來向社區表明這一點。這也將爲您遵循正確的程序贏得一些聲望點。 – jfriend00

0

我不確定你的代碼。但我通常使用空間來發送給用戶和socket的回調函數。這是使用回調,而不是return_login事件

io.on('connection', function(socket){ 
 
    socket.on('login', function(data, callback){ 
 
     
 
     // Using callback instead of return_login event 
 
     server_y.emit('login', data, function(responseData){ 
 
      
 
      // put this socket to room as name = user_id 
 
      socket.join(responseData.user_id); 
 
      
 
      // return result by callback 
 
      callback(responseData) 
 
     }); 
 
    }); 
 

 
}); 
 

 
// emit to exactly user_id with return_login event if you want 
 
io.to(user_id).emit('return_login', {key: 'ok'})

+0

我嘗試了類似的東西,但它不完全是我在找的東西。我很欣賞願意幫助,雖然:) – flakeyjake