如何使用socket.io向特定客户端发送消息

Niz*_* B. 85 javascript ajax jquery node.js socket.io

我从socket.io + node.js开始,我知道如何在本地发送消息和广播socket.broadcast.emit()功能: - 所有连接的客户端都收到相同的消息.

现在,我想知道如何向特定客户端发送私人消息,我的意思是一个套接字用于2人之间的私人聊天(客户端到客户端流).谢谢.

az7*_*7ar 241

您可以使用socket.io房间.从客户端发出一个事件(在这种情况下,"加入",可以是任何东西)与任何唯一标识符(电子邮件,id).

客户端:

var socket = io.connect('http://localhost');
socket.emit('join', {email: user1@example.com});
Run Code Online (Sandbox Code Playgroud)

现在,从服务器端使用该信息为该用户创建一个独特的空间

服务器端:

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.on('join', function (data) {
    socket.join(data.email); // We are using room of socket io
  });
});
Run Code Online (Sandbox Code Playgroud)

所以,现在每个用户都加入了以用户电子邮件命名的房间.因此,如果您想向特定用户发送您必须发送的消息

服务器端:

io.sockets.in('user1@example.com').emit('new_msg', {msg: 'hello'});
Run Code Online (Sandbox Code Playgroud)

客户端最后要做的就是收听"new_msg"事件.

客户端:

socket.on("new_msg", function(data) {
    alert(data.msg);
}
Run Code Online (Sandbox Code Playgroud)

我希望你明白这个主意.

  • 这个答案比目前接受的答案好很多.原因如下:1)您无需管理和清理全局客户端阵列.2)即使用户在同一页面上打开了多个选项卡,它也能正常工作.3)使用`socket.io-redis`可以很容易地扩展到使用节点集群(多个进程). (38认同)
  • 它不必是电子邮件我提到了任何唯一标识符 (3认同)
  • 请更改此行io.socket.in('user1@example.com').emit('new_msg',{msg:'hello'}); 像这样的io.sockets.in('user1@example.com').emit('new_msg',{msg:'hello'}); (2认同)
  • 对于所有连接,如何使{{email:user1@example.com}`有所不同?请问该应用程序的所有客户端都没有用户`user1 @ example.com`吗?我如何将其设为用户`user2 @ example.com`?第二个连接的客户端,所以我可以有不同的房间。抱歉,如果这是一个令人讨厌的问题。 (2认同)
  • 喜欢这个解决方案,但我相信这里的安全性受到了影响.如果我在客户端更改脚本中的电子邮件该怎么办?现在我也可以阅读其他私人消息.你在说什么? (2认同)
  • 我的问题是第二个用户将如何加入房间,因为上面的代码是用他们自己的电子邮件加入房间,而且他们的加入似乎并不常见 (2认同)

Ada*_*dam 91

当用户连接时,它应该使用必须唯一的用户名(例如电子邮件)向服务器发送消息.

一对用户名和套接字应该存储在这样的对象中:

var users = {
    'userA@example.com': [socket object],
    'userB@example.com': [socket object],
    'userC@example.com': [socket object]
}
Run Code Online (Sandbox Code Playgroud)

在客户端上,使用以下数据向服务器发出一个对象:

{
    to:[the other receiver's username as a string],
    from:[the person who sent the message as string],
    message:[the message to be sent as string]
}
Run Code Online (Sandbox Code Playgroud)

在服务器上,侦听消息.收到消息后,将数据发送给接收方.

users[data.to].emit('receivedMessage', data)
Run Code Online (Sandbox Code Playgroud)

在客户端上,侦听来自名为"receivedMessage"的服务器的发出,并通过读取数据来处理它来自何处以及发送的消息.

  • 如果您使用此解决方案,则必须了解:1.当用户断开连接时,您必须清理"用户"对象2.它不支持第二次连接 - 例如来自其他浏览器.因此,如果用户从另一个浏览器连接 - 旧连接将被覆盖. (25认同)
  • 我建议不要使用这个解决方案.我最终浪费了大量时间来克服这种方法的局限性.参见[@ az7ar的解决方案](http://stackoverflow.com/a/17535099/2901178)和[解释为什么它更好](http://stackoverflow.com/questions/17476294/how-to-send-a -message到一个-特定的客户端与 - 插座-IO#comment39387846_17535099). (10认同)

Tro*_*jan 26

当然: 简单地说,

这就是你需要的:

io.to(socket.id).emit("event", data);
Run Code Online (Sandbox Code Playgroud)

每当用户加入服务器时,将生成包括ID的套接字详细信息.这个ID确实有助于向特定的人发送消息.

首先我们需要将所有socket.id存储在数组中,

var people={};

people[name] =  socket.id;
Run Code Online (Sandbox Code Playgroud)

这里的名字是接收者名称.例:

people["ccccc"]=2387423cjhgfwerwer23;
Run Code Online (Sandbox Code Playgroud)

所以,现在我们可以在发送消息时使用接收者名称获取socket.id:

为此我们需要知道receivername.您需要向服务器发出接收者名称.

最后一件事是:

 socket.on('chat message', function(data){
io.to(people[data.receiver]).emit('chat message', data.msg);
});
Run Code Online (Sandbox Code Playgroud)

希望这对你有用.

祝好运!!

  • 但是如果用户同时与 2 个人聊天呢?来自两个用户的消息不会同时出现在两个窗口中吗? (2认同)
  • 如果有两个以上的用户,它将无法正常工作 (2认同)

Vla*_*jov 8

你可以参考socket.io 房间.当你握手套接字时 - 你可以将他加入到命名的房间,例如"user.#{userid}".

之后,您可以通过方便的名称向任何客户端发送私人消息,例如:

io.sockets.in('user.125').emit('new_message',{text:"Hello world"})

在上面的操作中,我们将"new_message"发送给用户"125".

谢谢.


Lal*_*han 6

正如az7ar 的回答说得很漂亮,但让我用 socket.io 房间让它更简单。请求具有唯一标识符的服务器加入服务器。在这里,我们使用电子邮件作为唯一标识符。

客户端Socket.io

socket.on('connect', function () {
  socket.emit('join', {email: user@example.com});
});
Run Code Online (Sandbox Code Playgroud)

当用户加入服务器时,为该用户创建一个房间

服务器Socket.io

io.on('connection', function (socket) {
   socket.on('join', function (data) {    
    socket.join(data.email);
  });
});
Run Code Online (Sandbox Code Playgroud)

现在我们都准备好加入了。让从服务器to机房发出一些东西,以便用户可以收听。

服务器Socket.io

io.to('user@example.com').emit('message', {msg: 'hello world.'});
Run Code Online (Sandbox Code Playgroud)

让我们message通过向客户端收听事件来完成主题

socket.on("message", function(data) {
  alert(data.msg);
});
Run Code Online (Sandbox Code Playgroud)

来自Socket.io 房间的参考

  • 看来你的答案是@az7ar的[答案](/sf/answers/1227456961/)的副本,如果你使用某人的答案并进行修改,请给予积分 (2认同)

小智 5

在我们公司的一个项目中,我们使用“房间”方法,它的名称是对话中所有用户的用户 ID 的组合作为唯一标识符(我们的实现更像是 Facebook 信使),例如:

|身份证 | 姓名 |1 | 斯科特 |2 | 苏珊

“房间”名称将是“1-2”(ID 以升序排列)并且在断开连接时 socket.io 会自动清理房间

通过这种方式,您只向那个房间发送消息,并且只向在线(连接)用户发送消息(整个服务器发送的包较少)。