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


96

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

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


抱歉psiphi75,但此链接未回复我的回答,不是重复的问题。
Nizar B.

1
@ psiphi75,这绝对不可能重复
softvar

1
受不了像@psiphi这样的人。你甚至是开发商吗?HTML5特定问题与独立库有何关系?对于它的价值,WebSockets不是Socket.io。Socket.io是一个可以使用WebSockets的库,但是我离题了。这也是与库有关的更具体的问题,即仅向特定客户端发送数据,而不是技术本身。
李维·罗伯茨


@ bugwheels94并非如此,这篇帖子来自2011年,因为nodejs在代码方面有大量更改。此帖子绝对是针对此问题的有效问题/答案。
Nizar B.

Answers:


102

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

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

var users = {
    'userA@example.com': [socket object],
    'userB@example.com': [socket object],
    'userC@example.com': [socket object]
}

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

{
    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]
}

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

users[data.to].emit('receivedMessage', data)

在客户端上,侦听来自服务器的名为“ receivedMessage”的发射,通过读取数据,您可以处理其来源和发送的消息。


27
如果使用此解决方案,则必须了解:1.当用户断开连接时,您必须清理“用户”对象。2.它不支持第二个连接-例如来自另一个浏览器。因此,如果用户从另一个浏览器连接-旧连接将被覆盖。
弗拉基米尔·库里约夫(Fladimir Kurijov)2013年

1
您如何将套接字对象存储在数据存储区中?我假设如果您有多个节点进程,则此操作将无效。
chovy 2013年


11
我建议不要使用此解决方案。我最终浪费了大量时间试图克服这种方法的局限性。请参阅@ az7ar的解决方案和此说明,以了解它为什么更好
丹尼尔·奎

@DanielQue +1。更好地使用本机功能。谢谢!
亚伦·勒里维耶

277

您可以使用socket.io房间。从客户端发出带有任何唯一标识符(电子邮件,ID)的事件(在这种情况下,“加入”可以是任何东西)。

客户端:

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

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

服务器端:

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

因此,现在每个用户都已加入一个以用户电子邮件命名的房间。因此,如果您想向特定用户发送消息,则只需

服务器端:

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

在客户端剩下要做的最后一件事是监听“ new_msg”事件。

客户端:

socket.on("new_msg", function(data) {
    alert(data.msg);
}

希望您能明白。


3
请更改此行io.socket.in('user1@example.com')。emit('new_msg',{msg:'hello'}); 像这样io.sockets.in('user1@example.com')。emit('new_msg',{msg:'hello'});
silvesterprabu 2014年

42
这个答案是比目前公认的答案更好。原因如下:1)您不必管理和清理全球范围的客户。2)即使用户在同一页面上打开了多个选项卡,它也可以工作。3)可以很容易地扩展为与节点集群(多个进程)一起使用socket.io-redis
丹尼尔·奎

2
您如何使{email: user1@example.com}所有连接都与众不同?不会去应用程序的所有客户端都具有用户user1@example.com了,我如何使它成为user2@example.com连接的第二个客户端的用户,因此我可以拥有不同的房间。抱歉,如果这是一个令人讨厌的问题。
杰克·

2
喜欢解决方案,但我认为这里的安全性受到了损害。如果我更改客户端脚本中的电子邮件该怎么办。现在,我也可以阅读其他私人消息。你在说什么?
Gopinath Shiva

3
它并没有被我的电子邮件中提到的唯一标识符
az7ar

32

当然: 简单地说,

这就是您需要的:

io.to(socket.id).emit("event", data);

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

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

var people={};

people[name] =  socket.id;

这里的名字是接收者的名字。例:

people["ccccc"]=2387423cjhgfwerwer23;

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

为此,我们需要知道接收方名称。您需要向服务器发送接收方名称。

最后一件事是:

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

希望这对您有效。

祝好运!!


您可以创建客户端和服务器端代码吗?我是scoket编程的新手。hmahajan.dmi@gmail.com
哈里斯·

@HARISH,请参考以下链接,解释了什么是真正的从客户端side..i希望这可以帮助你更多..发生socket.io/get-started/chat
木马

2
但是如果用户同时与2个人聊天,该怎么办。来自两个用户的消息都不会出现在两个窗口中吗?
莎朗·莫汉达斯

如果有两个以上的用户多了,就会不工作的权利
Mohhamad Hasham

每次用户连接套接字ID更改时,如果用户在多个选项卡中打开您的应用程序,它将获得对您已存储并发送到其他套接字连接的应用程序的响应
Vikas Kandari

8

您可以参考socket.io 房间。握手套接字时-您可以将他加入命名的房间,例如“ user。#{userid}”。

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

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

在上面的操作中,我们将“ new_message”发送给用户“ 125”。

谢谢。


嗨,队友,谢谢您的第一个回答,我将尝试一下,并让您知道,因为我不想建立聊天,而是想要像在Facebook网络上使用的私人Messenger。
Nizar B.

有人可以帮我解决这个问题,我真的很困,我想添加一个链接到我的套接字的用户名,并允许我的应用程序向特定用户发送消息,没有聊天室,这是一个像Messenger的Facebook。谢谢,如果你知道!
Nizar B.

首先,您必须了解该用户名在所有用户中必须是唯一的。第二个-您是否忘了在客户端订阅发出的消息?
弗拉基米尔·库里约夫(Fladimir Kurijov),

这样做的问题是您失去了使用回调的能力,因为在广播中不允许使用这些回调,这实际上是您在此处所做的,即在他的私人房间进行广播。
bluehallu 2014年

@VladimirKurijov,Katcha先生不想使用Rooms,我同意这不是解决他问题的方法。
miksiii

4

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

| id | 名称| 1 | 斯科特| 2 | 苏珊

“房间”名称将为“ 1-2”(ID按升序订购),并在断开套接字的情况下自动清除房间

这样,您仅向该房间发送消息,并且仅向在线(连接)用户发送消息(在整个服务器中发送的软件包更少)。


1

让我通过socket.io房间使其更简单。请求具有唯一标识符的服务器加入服务器。在这里,我们使用电子邮件作为唯一标识符。

客户端Socket.io

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

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

服务器Socket.io

io.on('connection', function (socket) {
   socket.on('join', function (data) {    
    socket.join(data.email);
  });
});

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

服务器Socket.io

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

让我们通过侦听message客户端的事件来最终确定主题

socket.on("message", function(data) {
  alert(data.msg);
});

Socket.io房间的参考

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.