我编写了一段代码,用于向所有用户广播一条消息:
// websocket and http servers
var webSocketServer = require('websocket').server;
...
...
var clients = [ ];
var server = http.createServer(function(request, response) {
// Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
...
});
var wsServer = new webSocketServer({
// WebSocket server is tied to a HTTP server.
httpServer: server
});
// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
...
var connection = request.accept(null, request.origin);
var index = clients.push(connection) - 1;
...
请注意:
- 我没有任何用户参考,只有一个连接。
- 所有用户连接都存储在
array
中。
目标:假设Node.js服务器想要发送一个消息给一个特定的客户端(John)。NodeJs服务器如何知道John有哪个连接?Node.js服务器甚至不认识John。它只看到连接。
所以,我认为现在,我不应该只通过连接来存储用户,相反,我需要存储一个对象,它将包含userId
和connection
对象。
:
当页面加载完成(DOM就绪)-建立与Node.js服务器的连接。
当Node.js服务器接受连接时-生成一个唯一的字符串并将其发送给客户端浏览器。将用户连接和唯一字符串存储在对象中。例:
{UserID:"6", value: {connectionObject}}
在客户端,当此消息到达时-将其存储在隐藏字段或cookie中。(用于将来对NodeJs服务器的请求)
当服务器想要发送消息给John时:
在字典中查找john的UserID,并通过相应的连接发送消息。
请注意这里没有涉及asp.net服务器代码(在消息机制中)。只有NodeJs .*
问题:
这条路对吗?
这不仅是正确的方法,而且是唯一的方法。基本上每个连接都需要一个唯一的ID。否则你将无法识别它们,就这么简单。
如何表示它是另一回事。用id
和connection
属性创建一个对象是一个很好的方法(我肯定会这样做)。您也可以将id
直接附加到连接对象。
还要记住,如果你想要用户之间的通信,那么你必须发送目标用户的ID,也就是说,当用户A想要发送消息给用户B,那么显然A必须知道B的ID
这是一个简单的聊天服务器私人/直接消息。
package.json
{
"name": "chat-server",
"version": "0.0.1",
"description": "WebSocket chat server",
"dependencies": {
"ws": "0.4.x"
}
}
server.js
var webSocketServer = new (require('ws')).Server({port: (process.env.PORT || 5000)}),
webSockets = {} // userID: webSocket
// CONNECT /:userID
// wscat -c ws://localhost:5000/1
webSocketServer.on('connection', function (webSocket) {
var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
webSockets[userID] = webSocket
console.log('connected: ' + userID + ' in ' + Object.getOwnPropertyNames(webSockets))
// Forward Message
//
// Receive Example
// [toUserID, text] [2, "Hello, World!"]
//
// Send Example
// [fromUserID, text] [1, "Hello, World!"]
webSocket.on('message', function(message) {
console.log('received from ' + userID + ': ' + message)
var messageArray = JSON.parse(message)
var toUserWebSocket = webSockets[messageArray[0]]
if (toUserWebSocket) {
console.log('sent to ' + messageArray[0] + ': ' + JSON.stringify(messageArray))
messageArray[0] = userID
toUserWebSocket.send(JSON.stringify(messageArray))
}
})
webSocket.on('close', function () {
delete webSockets[userID]
console.log('deleted: ' + userID)
})
})
指令要测试它,运行npm install
安装ws
。然后,要启动聊天服务器,在一个Terminal选项卡中运行node server.js
(或npm start
)。然后,在另一个Terminal选项卡中,运行wscat -c ws://localhost:5000/1
,其中1
是连接用户的用户ID。然后,在第三个Terminal选项卡中,运行wscat -c ws://localhost:5000/2
,然后,要从用户2
发送消息给1
,输入["1", "Hello, World!"]
.
这个聊天服务器非常简单。
- 持久性
它不把消息存储到数据库中,比如PostgreSQL。因此,要向其发送消息的用户必须连接到服务器才能接收消息。
- 安全
这是不安全的。
如果我知道服务器的URL和Alice的用户ID,那么我可以冒充Alice,即,以她的身份连接到服务器,允许我接收她的新传入消息,并将她的消息发送给任何我也知道用户ID的用户。要使其更安全,请修改服务器以在连接时接受您的访问令牌(而不是您的用户ID)。然后,服务器可以从您的访问令牌中获取您的用户ID并对您进行身份验证。
我不确定它是否支持WebSocket安全(
wss://
)连接,因为我只在localhost
上测试了它,我不确定如何从localhost
安全地连接。
使用ws
版本3或以上版本的用户。如果您想使用@ma11hew28提供的答案,只需按如下方式更改此块。
webSocketServer.on('connection', function (webSocket) {
var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
webSocketServer.on('connection', function (webSocket, req) {
var userID = parseInt(req.url.substr(1), 10)
ws
包已经将upgradeReq
移动到请求对象,您可以查看以下链接了解更多细节。
参考:https://github.com/websockets/ws/issues/1114
我想分享一下我所做的。希望没有浪费你的时间。
我创建了包含字段ID, IP,用户名,logintime和logouttime的数据库表。当用户登录时,logintime将是当前的unix时间戳unix。当连接开始在websocket数据库检查最大登录时间。它将在用户登录后显示。
当用户注销时,它将存储当前的注销时间。用户将成为离开应用程序的人。
每当有新消息时,比较Websocket ID和IP并显示相关的用户名。以下是示例代码…
// when a client connects
function wsOnOpen($clientID) {
global $Server;
$ip = long2ip( $Server->wsClients[$clientID][6] );
require_once('config.php');
require_once CLASSES . 'class.db.php';
require_once CLASSES . 'class.log.php';
$db = new database();
$loga = new log($db);
//Getting the last login person time and username
$conditions = "WHERE which = 'login' ORDER BY id DESC LIMIT 0, 1";
$logs = $loga->get_logs($conditions);
foreach($logs as $rows) {
$destination = $rows["user"];
$idh = md5("$rows[user]".md5($rows["time"]));
if ( $clientID > $rows["what"]) {
$conditions = "ip = '$ip', clientID = '$clientID'
WHERE logintime = '$rows[time]'";
$loga->update_log($conditions);
}
}
...//rest of the things
}
有趣的帖子(类似于我正在做的)。我们正在制作一个API(用c#)来连接分发器和WebSockets,对于每个分发器,我们创建一个ConcurrentDictionary来存储WebSocket和DispenserId,使每个分发器创建一个WebSocket并在没有线程问题的情况下使用它(调用WebSocket上的特定函数,如GetSettings或RequestTicket)。您的例子的区别是使用ConcurrentDictionary而不是数组来隔离每个元素(从未尝试在javascript中这样做)。最好的祝福,