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

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

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

144440 次浏览

您可以参考 socket.io 房间。 当您握手插座-您可以加入他们的命名房间,例如 user.#{userid}

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

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

在上面的操作中,我们向用户“125”发送“ new _ message”。

谢谢。

当用户连接时,它应该向服务器发送一个用户名必须是唯一的消息,如电子邮件。

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

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”的服务器发出的数据,通过读取数据,您可以处理数据来自谁以及发送的消息。

你可以用 Socket.io 的房间。从客户端发出一个带有任何唯一标识符(email,id)的事件(在本例中,“ join”可以是任何东西)。

客户端:

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

我希望你能明白。

In a project of our company we are using "rooms" approach and it's name is a combination of user ids of all users in a conversation as a unique identifier (our implementation is more like facebook messenger), example:

名字 斯科特 苏珊

"room" name will be "1-2" (ids are ordered Asc.) and on disconnect socket.io automatically cleans up the room

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

当然: 很简单,

这就是你需要的:

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

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

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

var people={};


people[name] =  socket.id;

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

people["ccccc"]=2387423cjhgfwerwer23;

因此,现在我们可以在发送消息时获得带有接收方名称的 socket.id:

为此,我们需要知道接收方的名称。

final thing is:

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

希望这对你有用。

祝你好运! !

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

Client 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 房间的参考文献

下面是 Android Client + Socket IO Server 的完整解决方案(大量代码但是可以工作)。在套接字输入法方面,似乎缺乏对 Android 和 IOS 的支持,这在某种程度上是一个悲剧。

基本上是 通过连接 mysql 或 mongo 中的用户惟一 ID 创建一个房间名称,然后对其进行排序(在 Android Client 中完成并发送到服务器)。所以每一对都有一个独特的但是在双人房间中很常见的名字。那就去那个房间聊天吧。

快速参考如何在 Android 中创建空间

 // Build The Chat Room
if (Integer.parseInt(mySqlUserId) < Integer.parseInt(toMySqlUserId)) {
room = "ic" + mySqlUserId + toMySqlUserId;
} else {
room = "ic" + toMySqlUserId + mySqlUserId;
}

全部工作

Package Json

"dependencies": {
"express": "^4.17.1",
"socket.io": "^2.3.0"
},
"devDependencies": {
"nodemon": "^2.0.6"
}

套接字 IO 服务器

app = require('express')()
http = require('http').createServer(app)
io = require('socket.io')(http)


app.get('/', (req, res) => {


res.send('Chat server is running on port 5000')
})


io.on('connection', (socket) => {


// console.log('one user connected ' + socket.id);


// Join Chat Room
socket.on('join', function(data) {


console.log('======Joined Room========== ');
console.log(data);


// Json Parse String To Access Child Elements
var messageJson = JSON.parse(data);
const room = messageJson.room;
console.log(room);


socket.join(room);


});


// On Receiving Individual Chat Message (ic_message)
socket.on('ic_message', function(data) {
console.log('======IC Message========== ');
console.log(data);


// Json Parse String To Access Child Elements
var messageJson = JSON.parse(data);
const room = messageJson.room;
const message = messageJson.message;


console.log(room);
console.log(message);


// Sending to all clients in room except sender
socket.broadcast.to(room).emit('new_msg', {
msg: message
});


});


socket.on('disconnect', function() {
console.log('one user disconnected ' + socket.id);
});


});


http.listen(5000, () => {


console.log('Node app is running on port 5000')
})

Android Socket IO 类

public class SocketIOClient {


public Socket mSocket;


{
try {
mSocket = IO.socket("http://192.168.1.5:5000");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}


public Socket getSocket() {
return mSocket;
}
}

Android Activity

public class IndividualChatSocketIOActivity extends AppCompatActivity {


// Activity Number For Bottom Navigation Menu
private final Context mContext = IndividualChatSocketIOActivity.this;


// Strings
private String mySqlUserId;
private String toMySqlUserId;


// Widgets
private EditText etTextMessage;
private ImageView ivSendMessage;


// Socket IO
SocketIOClient socketIOClient = new SocketIOClient();
private String room;


@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);


// Widgets
etTextMessage = findViewById(R.id.a_chat_et_text_message);
ivSendMessage = findViewById(R.id.a_chat_iv_send_message);


// Get The MySql UserId from Shared Preference
mySqlUserId = StartupMethods.getFromSharedPreferences("shared",
"id",
mContext);


// Variables From Individual List Adapter
Intent intent = getIntent();


if (intent.hasExtra("to_id")) {


toMySqlUserId = Objects.requireNonNull(Objects.requireNonNull(getIntent().getExtras())
.get("to_id"))
.toString();
}


// Build The Chat Room
if (Integer.parseInt(mySqlUserId) < Integer.parseInt(toMySqlUserId)) {
room = "ic" + mySqlUserId + toMySqlUserId;
} else {
room = "ic" + toMySqlUserId + mySqlUserId;
}


connectToSocketIO();


joinChat();


leaveChat();


getChatMessages();


sendChatMessages();


}


@Override
protected void onPause() {
super.onPause();


}


private void connectToSocketIO() {


socketIOClient.mSocket = socketIOClient.getSocket();
socketIOClient.mSocket.on(Socket.EVENT_CONNECT_ERROR,
onConnectError);
socketIOClient.mSocket.on(Socket.EVENT_CONNECT_TIMEOUT,
onConnectError);
socketIOClient.mSocket.on(Socket.EVENT_CONNECT,
onConnect);
socketIOClient.mSocket.on(Socket.EVENT_DISCONNECT,
onDisconnect);
socketIOClient.mSocket.connect();
}


private void joinChat() {


// Prepare To Send Data Through WebSockets
JSONObject jsonObject = new JSONObject();


// Header Fields
try {


jsonObject.put("room",
room);


socketIOClient.mSocket.emit("join",
String.valueOf(jsonObject));


} catch (JSONException e) {
e.printStackTrace();
}


}


private void leaveChat() {
}


private void getChatMessages() {


socketIOClient.mSocket.on("new_msg",
new Emitter.Listener() {
@Override
public void call(Object... args) {
try {
JSONObject messageJson = new JSONObject(args[0].toString());
String message = String.valueOf(messageJson);


runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(IndividualChatSocketIOActivity.this,
message,
Toast.LENGTH_SHORT)
.show();
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}


private void sendChatMessages() {


ivSendMessage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {


String message = etTextMessage.getText()
.toString()
.trim();


// Prepare To Send Data Thru WebSockets
JSONObject jsonObject = new JSONObject();


// Header Fields
try {
jsonObject.put("room",
room);


jsonObject.put("message",
message);


socketIOClient.mSocket.emit("ic_message",
String.valueOf(jsonObject));


} catch (JSONException e) {
e.printStackTrace();
}


}
});
}


public Emitter.Listener onConnect = new Emitter.Listener() {
@Override
public void call(Object... args) {


runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(IndividualChatSocketIOActivity.this,
"Connected To Socket Server",
Toast.LENGTH_SHORT)
.show();


}
});


Log.d("TAG",
"Socket Connected!");
}
};


private Emitter.Listener onConnectError = new Emitter.Listener() {
@Override
public void call(Object... args) {


runOnUiThread(new Runnable() {
@Override
public void run() {


}
});
}
};
private Emitter.Listener onDisconnect = new Emitter.Listener() {
@Override
public void call(Object... args) {


runOnUiThread(new Runnable() {
@Override
public void run() {


}
});
}
};


}

安卓格拉德

// SocketIO
implementation ('io.socket:socket.io-client:1.0.0') {
// excluding org.json which is provided by Android
exclude group: 'org.json', module: 'json'
}

我所做的不是制作房间 (因为您只想将消息发送给一个人),而是制作一个内存数组:

clientSessions: Map<string, UserIdentifier> = new Map()

我这样做是为了我的用例,在这个用例中,我希望根据我设置的标识符获得所需的套接字 ID。映射中的键将是我设置的标识符,该值包含连接的套接字的 ID。请参见下面的服务器端代码。

Client-side:

const socket = io('http://localhost:3200', {query: {randomKeyID: '123'}});

服务器端:

  handleDisconnect(client: Socket) {
const query = client.handshake.query;
const randomKeyID = <string> query.randomKeyID
this.clientSessions.delete(randomKeyID);
console.log(`Client disconnected: ${client.id}`);
}


handleConnection(client: Socket, ...args: any[]) {
const query = client.handshake.query;
const user: UserIdentifier = {
id: client.id,
randomKeyID: <string> query.randomKeyID
}
this.clientSessions.set(user.randomKeyID, user);
console.log(`Client connected: ${client.id}`);
}

在服务器端添加了这一功能,以方便地访问 websocket (type Server 来自 socket.io):

  @WebSocketServer()
server: Server;

So, if I want to send to a particular client, I can:

const { randomKeyID } = this.clientSessions.get(something);
this.server.to(randomKeyID).emit('clientListener', 'Hello');