Html 使用 webSocket 向特定连接的用户发送消息?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16280747/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 08:00:15  来源:igfitidea点击:

Sending message to a specific connected users using webSocket?

javascripthtmlnode.jswebsocket

提问by Royi Namir

I wrote a code for broadcasting a message to allusers:

我写了一个代码来向所有用户广播消息:

// 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;
...

Please notice:

请注意:

  • I don't have any user reference but only a connection .
  • All users connection are stored in an array.
  • 我没有任何用户参考,只有一个 connection 。
  • 所有用户连接都存储在一个array.

Goal: Let's say that the Node.js server wants to send a message to a specific client (John). How would the NodeJs server know which connection John has? The Node.js server doesn't even know John. all it sees is the connections.

目标:假设 Node.js 服务器想要向特定客户端 (John) 发送消息。NodeJs 服务器如何知道 John 有哪个连接?Node.js 服务器甚至不认识 John。它看到的只是连接。

So, I believe that now, I shouldn't store users only by their connection, instead, I need to store an object, which will contain the userIdand the connectionobject.

所以,我相信现在,我不应该只通过他们的连接来存储用户,相反,我需要存储一个对象,该对象将包含userIdconnection对象。

Idea:

主意:

  • When the page finishes loading (DOM ready) - establish a connection to the Node.js server.

  • When the Node.js server accept a connection - generate a unique string and send it to the client browser. Store the user connection and the unique string in an object. e.g. {UserID:"6", value: {connectionObject}}

  • At client side, when this message arrives - store it in a hidden field or cookie. (for future requests to the NodeJs server )

  • 当页面完成加载(DOM 就绪)时 - 建立到 Node.js 服务器的连接。

  • 当 Node.js 服务器接受连接时 - 生成一个唯一的字符串并将其发送到客户端浏览器。将用户连接和唯一字符串存储在一个对象中。例如{UserID:"6", value: {connectionObject}}

  • 在客户端,当此消息到达时 - 将其存储在隐藏字段或 cookie 中。(用于将来对 NodeJs 服务器的请求)



When the server wants to send a message to John:

当服务器想要向 John 发送消息时:

  • Find john's UserID in the dictionary and send a message by the corresponding connection.

  • please notice there is no asp.net server code invloced here (in the message mechanism). only NodeJs .*

  • 在字典中找到john的UserID,通过对应的连接发送消息。

  • 请注意这里(在消息机制中)没有 invloced asp.net 服务器代码。只有 NodeJs .*

Question:

题:

Is this the right way to go?

这是正确的方法吗?

采纳答案by freakish

This is not only the right way to go, but the only way. Basically each connection needs a unique ID. Otherwise you won't be able to identify them, it's as simple as that.

这不仅是正确的方法,而且是唯一的方法。基本上每个连接都需要一个唯一的 ID。否则你将无法识别它们,就这么简单。

Now how you will represent it it's a different thing. Making an object with idand connectionproperties is a good way to do that ( I would definitely go for it ). You could also attach the iddirectly to connection object.

现在你将如何表示它是另一回事。用idconnection属性创建一个对象是一个很好的方法(我肯定会去做)。您还可以将id直接附加到连接对象。

Also remember that if you want communication between users, then you have to send target user's ID as well, i.e. when user A wants to send a message to user B, then obviously A has to know the ID of B.

还要记住,如果您想要用户之间的通信,那么您还必须发送目标用户的 ID,即当用户 A 想要向用户 B 发送消息时,显然 A 必须知道 B 的 ID。

回答by ma11hew28

Here's a simple chat server private/direct messaging.

这是一个简单的聊天服务器私人/直接消息传递。

package.json

package.json

{
  "name": "chat-server",
  "version": "0.0.1",
  "description": "WebSocket chat server",
  "dependencies": {
    "ws": "0.4.x"
  }
}

server.js

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

Instructions

指示

To test it out, run npm installto install ws. Then, to start the chat server, run node server.js(or npm start) in one Terminal tab. Then, in another Terminal tab, run wscat -c ws://localhost:5000/1, where 1is the connecting user's user ID. Then, in a third Terminal tab, run wscat -c ws://localhost:5000/2, and then, to send a message from user 2to 1, enter ["1", "Hello, World!"].

要测试它,请运行npm install以安装ws. 然后,要启动聊天服务器,请在一个终端选项卡中运行node server.js(或npm start)。然后,在另一个终端选项卡中,运行wscat -c ws://localhost:5000/1,其中1是连接用户的用户 ID。然后,在第三个终端选项卡中,运行wscat -c ws://localhost:5000/2,然后从用户2向发送消息1,输入["1", "Hello, World!"]

Shortcomings

缺点

This chat server is very simple.

这个聊天服务器非常简单。

  • Persistence

    It doesn't store messages to a database, such as PostgreSQL. So, the user you're sending a message to must be connected to the server to receive it. Otherwise, the message is lost.

  • Security

    It is insecure.

    • If I know the server's URL and Alice's user ID, then I can impersonate Alice, ie, connect to the server as her, allowing me to receive her new incoming messages and send messages from her to any user whose user ID I also know. To make it more secure, modify the server to accept your access token (instead of your user ID) when connecting. Then, the server can get your user ID from your access token and authenticate you.

    • I'm not sure if it supports a WebSocket Secure (wss://) connection since I've only tested it on localhost, and I'm not sure how to connect securely from localhost.

  • 坚持

    它不会将消息存储到数据库,例如 PostgreSQL。因此,您要向其发送消息的用户必须连接到服务器才能接收消息。否则,消息将丢失。

  • 安全

    这是不安全的。

    • 如果我知道服务器的 URL 和 Alice 的用户 ID,那么我可以模拟 Alice,即以她的身份连接到服务器,允许我接收她的新传入消息并将消息从她发送给我也知道用户 ID 的任何用户。为了使其更安全,请修改服务器以在连接时接受您的访问令牌(而不是您的用户 ID)。然后,服务器可以从您的访问令牌中获取您的用户 ID 并对您进行身份验证。

    • 我不确定它是否支持 WebSocket Secure ( wss://) 连接,因为我只在 上对其进行了测试localhost,而且我不确定如何从localhost.

回答by Dylandy Chang

For people using wsversion 3 or above. If you want to use the answer provided by @ma11hew28, simply change this block as following.

对于使用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)

wspackage has moved upgradeReq to request object and you can check the following link for further detail.

ws包已将 upgradeReq 移动到请求对象,您可以查看以下链接以获取更多详细信息。

Reference: https://github.com/websockets/ws/issues/1114

参考:https: //github.com/websockets/ws/issues/1114

回答by tashi

I would like to share what I have done. Hope it doesn't waste your time.

我想分享我所做的。希望不要浪费你的时间。

I created database table holding field ID, IP, username, logintime and logouttime. When a user logs in logintime will be currect unixtimestamp unix. And when connection is started in websocket database checks for largest logintime. It will be come user logged in.

我创建了包含字段 ID、IP、用户名、登录时间和注销时间的数据库表。当用户登录时,logintime 将是当前的 unixtimestamp unix。当在 websocket 数据库中启动连接时,检查最大登录时间。它将是用户登录。

And for when user logs out it will store currect logouttime. The user will become who left the app.

当用户注销时,它将存储当前的注销时间。用户将成为离开应用程序的人。

Whenever there is new message, Websocket ID and IP are compared and related username will be displayed. Following are sample code...

每当有新消息时,都会比较 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
} 

回答by wolf354

interesting post (similar to what I am doing). We are making an API (in C#) to connect dispensers with WebSockets, for each dispenser we create a ConcurrentDictionary that stores the WebSocket and the DispenserId making it easy for each Dispenser to create a WebSocket and use it afterwards without thread problems (invoking specific functions on the WebSocket like GetSettings or RequestTicket). The difference for you example is the use of ConcurrentDictionary instead of an array to isolate each element (never attempted to do such in javascript). Best regards,

有趣的帖子(类似于我在做什么)。我们正在制作一个 API(在 C# 中)来将分配器与 WebSockets 连接起来,对于每个分配器,我们创建一个 ConcurrentDictionary 来存储 WebSocket 和 DispenserId 使每个分配器都可以轻松创建 WebSocket 并在之后使用它而不会出现线程问题(调用特定函数)在 WebSocket 上,如 GetSettings 或 RequestTicket)。您示例的不同之处在于使用 ConcurrentDictionary 而不是数组来隔离每个元素(从未尝试在 javascript 中这样做)。此致,