2012-11-13 43 views
33

我想使用與node.js套接字,我成功了,但我不知道如何區分我的代碼中的客戶端。 關於插座的部分是這樣的:webSocketServer node.js如何區分客戶端

var WebSocketServer = require('ws').Server, 
    wss = new WebSocketServer({port: 8080}); 
wss.on('connection', function(ws) { 
    ws.on('message', function(message) { 
     console.log('received: %s', message); 
     ws.send(message); 
    }); 
    ws.send('something'); 
}); 

此代碼工作正常與我的客戶JS。

但我想發送一條消息給特定用戶或所有在我的服務器上打開套接字的用戶。

在我的情況下,我發送消息作爲客戶端,我收到一個響應,但其他用戶什麼也沒有顯示。

我想舉個例子,用戶1通過webSocket發送一條消息到服務器,我發送一個通知給user2,他的套接字打開。

+0

如何_you_定義哪些連接是「用戶1」,並且是「用戶2」? – lanzz

+0

我不知道真的,我想在給用戶連接時給一種socketSession – Ajouve

+2

好吧,只要你知道連接的_user身份(例如,當你的用戶發送他的用戶名作爲消息),你可以在字典中存儲一個有名的引用(例如'connections [username] = ws'),然後在其他地方,你可以做一些類似'connections [username] .send(message)' – lanzz

回答

30

您可以簡單地將用戶標識分配給數組CLIENTS [],這將包含所有用戶。您可以直接發送消息給所有用戶,如下所示:

var WebSocketServer = require('ws').Server, 
    wss = new WebSocketServer({port: 8080}), 
    CLIENTS=[]; 

wss.on('connection', function(ws) { 
    CLIENTS.push(ws); 
    ws.on('message', function(message) { 
     console.log('received: %s', message); 
     sendAll(message); 
    }); 
    ws.send("NEW USER JOINED"); 
}); 

function sendAll (message) { 
    for (var i=0; i<CLIENTS.length; i++) { 
     CLIENTS[i].send("Message: " + message); 
    } 
} 
+1

如果您來回發送客戶端的唯一ID,您還可以獲取消息的源客戶端。 –

+15

此解決方案無法縮放,因爲變量CLIENTS駐留在NodeJS的單個進程中。即使我們通過分叉多個進程來利用多個內核,CLIENTS也不是共享內存分配,每個進程都維護着自己的CLIENTS列表。因此,它需要後續連接與同一過程進行交談。 –

+1

你可以發佈客戶端嗎? – johannesMatevosyan

6

This code snippet在Worlize服務器真的幫了我很多。即使你使用ws,代碼也應該很容易適應。我在這裏選擇的重要組成部分:

// initialization 
var connections = {}; 
var connectionIDCounter = 0; 

// when handling a new connection 
connection.id = connectionIDCounter ++; 
connections[connection.id] = connection; 
// in your case you would rewrite these 2 lines as 
ws.id = connectionIDCounter ++; 
connections[ws.id] = ws; 

// when a connection is closed 
delete connections[connection.id]; 
// in your case you would rewrite this line as 
delete connections[ws.id]; 

現在您可以輕鬆創建一個廣播()和sendToConnectionId()函數如圖所示鏈接的代碼。

希望有所幫助。

+0

一個'for in'循環將需要用於廣播,而不是循環的標準,因爲(關聯)數組中存在「空洞」。 – Tobiq

2

我從ws對象使用fd。它應該是每個客戶唯一的。

var clientID = ws._socket._handle.fd; 

當我打開一個新的瀏覽器選項卡時,我得到一個不同的數字。

第一WS有11個,下有12

+7

我認爲如果用戶離開並且另一個用戶加入,文件描述符fd可以被重新使用......實質上,它們可能會被回收利用 – user772401

+0

如果使用,您可以從會話中刪除它,並且即使使用相同編號在會話表 – muni764

+0

中會出現未填充的密鑰,可能會出現這樣的問題:在不知情的情況下,_handle將會消失,並且無法將其從表格中移除,可能是您可以將句柄保存在ws中? – muni764

6

這取決於它的WebSocket您使用。例如,最快的國家之一,在這裏找到:https://github.com/websockets/ws能夠通過這種方法做廣播:

var WebSocketServer = require('ws').Server, 
    wss = new WebSocketServer({host:'xxxx',port:xxxx}), 
    users = []; 
wss.broadcast = function broadcast(data) { 
wss.clients.forEach(function each(client) { 
    client.send(data); 
}); 
}; 

然後在你的代碼後,你可以使用wss.broadcast(消息)發送到所有。對於發送PM給個人用戶,我做了以下操作:

(1)在我發送到服務器的消息中,我包含用戶名 (2)然後,在onMessage中,將websocket保存到數組中用戶名,然後由用戶名以後檢索:

wss.on('connection', function(ws) { 

    ws.on('message', function(message) { 

     users[message.userName] = ws; 

(3)要發送到隨後可以執行用戶[用戶名]。發送(消息)的特定用戶;

+0

你可以提供任何鏈接代碼,你包括用戶名? – johannesMatevosyan

+0

在客戶端上,當你發送消息時,你可以創建一個JSON對象,然後像下面這樣對其進行字符串化:var sendObject = {userName:「Tim」,pm:true,message:「你好嗎? ws.send(JSON.stringify(使用SendObject));另外,在Einaros中,您可以在標頭中發送json有效內容,如下所示:WS.open(uri,[JSON.stringify({userName:「Tim」})]);然後你可以使用ws.upgradeReq.headers在服務器上解析它,並且可以通過JSON.parse將字符串轉換回它的對象。我已經使用這種方法來創建用戶組,但它也可以用來存儲用戶數組。 –

+0

我有類似的問題,但解決不了,你能看看嗎? http://stackoverflow.com/questions/35535700/websockets-send-messages-and-notifications-to-all-clients-except-sender – johannesMatevosyan

0

客戶端如果您的意思是打開連接,那麼您可以使用ws.upgradeReq.headers['sec-websocket-key']作爲標識符。並將所有套接字對象保存在一個數組中。

但是,如果你想識別你的用戶,那麼你需要添加用戶特定的數據到套接字對象。

3

您可以檢查連接對象。它爲每個連接的客戶端都有內置的標識;你可以在這裏找到:

let id=ws._ultron.id; 
console.log(id); 
+0

你怎麼知道Ultron.id是獨一無二的?我找不到與此相關的任何內容。 – adelriosantiago

+0

使用不同的連接自己嘗試一下。 –

9

在你的NodeJS可以直接修改WS客戶端並添加自定義爲每個客戶單獨的屬性。你也有一個全局變量wss.clients,可以在任何地方使用。請嘗試下面的代碼,並嘗試在真皮休閒兩個客戶端連接:

var WebSocketServer = require('ws').Server; 
var wss = new WebSocketServer({ 
    server: httpsServer 
}); 


wss.getUniqueID = function() { 
    function s4() { 
     return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); 
    } 
    return s4() + s4() + '-' + s4(); 
}; 

wss.on('connection', function connection(ws, req) { 
    ws.id = wss.getUniqueID(); 

    wss.clients.forEach(function each(client) { 
     console.log('Client.ID: ' + client.id); 
    }); 
}); 

您還可以在客戶端連接URL直接傳遞參數:

https://myhost:8080?myCustomParam=1111&myCustomID=2222

在連接功能,您可以得到這些參數並將這些參數直接分配給您的ws客戶端:

wss.on('connection', function connection(ws, req) { 

    const parameters = url.parse(req.url, true); 

    ws.uid = wss.getUniqueID(); 
    ws.chatRoom = {uid: parameters.query.myCustomID}; 
    ws.hereMyCustomParameter = parameters.query.myCustomParam; 
} 
+0

爲什麼這在任何地方都沒有提及?很好的答案。 – Sam

+0

直接傳遞參數對我來說是很好的解決方案 – Hylle

+0

有沒有辦法做到這一點,而不會突變'ws'?在執行'ws.clients.values()'時,是否有辦法從該列表中獲取請求? – Sawtaytoes

0

此處可能的解決方案之一可能是追加維護在用戶標識之前放置,因此我們可以將具有相同用戶標識但位於不同設備上的多個用戶分開。

ws://xxxxxxx:9000/userID/<<deviceId>>