我知道 Socket 可以指定IP端口去发送消息给客户端,如果我在 WebSocket 想要指定发送消息给某个连接中的Client,如何实现呢?
在 WebSocket 中,可以通过存储连接的方式来实现向特定客户端发送消息。
当客户端连接到 WebSocket 时,服务器会为每个客户端创建一个唯一的标识符,称为“连接 ID”或“会话 ID”。这个连接 ID 可以用于标识客户端和存储与该客户端相关的信息,例如其订阅的频道等。
有多种方法可以将连接 ID 存储在服务器端。以下是其中两种常见的方法:
使用 Map 数据结构
使用 Map 数据结构可以将连接 ID 映射到客户端对象上。在客户端连接到 WebSocket 并建立连接时,我们可以将其连接 ID 和客户端对象存储到一个 Map 中。当需要向特定客户端发送消息时,只需要从 Map 中获取对应的客户端对象即可。
以下是使用 Map 存储连接 ID 的示例代码:
javascript
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 8080 })
// 存储连接 ID 和客户端对象的 Map
const clients = new Map()
wss.on('connection', (ws) => {
// 生成连接 ID
const connId = uuid.v4()
// 存储连接 ID 和客户端对象
clients.set(connId, ws)
ws.on('message', (message) => {
console.log(`Received message from client ${connId}: ${message}`)
})
ws.on('close', () => {
// 移除连接 ID 和客户端对象
clients.delete(connId)
})
})
function sendToClient(connId, message) {
// 从 Map 中获取客户端对象
const client = clients.get(connId)
if (client && client.readyState === WebSocket.OPEN) {
client.send(message)
}
}
在这个示例中,我们使用了一个 Map 对象 clients 来存储连接 ID 和客户端对象的映射关系。当客户端连接到 WebSocket 并建立连接时,我们生成一个唯一的连接 ID,并将其与客户端对象存储在 Map 中。当需要向特定客户端发送消息时,我们只需要从 Map 中获取对应的客户端对象并调用它的 send 方法即可。
在客户端对象上添加属性
另一种方法是在客户端对象上添加一个属性来存储连接 ID。在客户端连接到 WebSocket 并建立连接时,我们可以将其连接 ID 存储在客户端对象的属性中。当需要向特定客户端发送消息时,只需要遍历所有客户端对象,找到具有指定连接 ID 的客户端对象并调用其 send 方法即可。
以下是在客户端对象上添加属性来存储连接 ID 的示例代码:
javascript
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 8080 })
wss.on('connection', (ws) => {
// 生成连接 ID
const connId = uuid.v4()
// 将连接 ID 存储在客户端对象上
ws.connId = connId
ws.on('message', (message) => {
console.log(`Received message from client ${ws.connId}: ${message}`)
})
ws.on('close', () => {
// 移除连接 ID
delete ws.connId
})
})
function sendToClient(connId, message) {
wss.clients.forEach((client) => {
if (client.connId === connId && client.readyState === WebSocket.OPEN) {
client.send(message)
}
})
}
在这个示例中,我们将连接 ID 存储在客户端对象的 connId 属性上。当需要向特定客户端发送消息时,我们遍历所有客户端对象,找到具有指定连接 ID 的客户端对象并调用其 send 方法即可。
@ServerEndpoint :类似与servlet中的 RequestMapping
@OnOpen:类似与servlet中的 init()初始化
@OnClose:类似与servlet中的destroy() 销毁
@OnMessage:类似于servlet中的service请求 (意思就是发送数据的方式 @doPost()/ @doGet() 组合)
WebSocket 中可以通过获取连接实例来发送消息给某个 Client。具体实现步骤如下:
在服务端保存 WebSocket 连接实例,可以将连接实例存储在数组、字典或其他数据结构中,方便后续根据需要获取相应的连接实例。
在服务端监听连接实例的消息事件,可以在回调函数中编写处理逻辑,比如根据客户端传输的消息数据来选择要发送给哪个 Client。
在服务端向指定的连接实例发送数据,可以通过获取要发送的连接实例来实现。例如,可以通过数组下标、客户端 ID 或其他标识符来获取连接实例,然后使用 send 方法发送数据。
以下是具体实现的伪代码:
// Step 1: Save websocket connection instances in an array
var connections = [];
ws.on('connection', function(connection) { connections.push(connection); });
// Step 2: Handle incoming messages and send responses
ws.on('message', function(message) { // Parse message data to extract target client identifier var targetId = message.targetId; var payload = message.payload;
// Find the target connection based on identifier var targetConnection = connections.find(function(connection) { return connection.clientId === targetId; });
// Send the payload to the target client targetConnection.send(payload); });
// Step 3: Send data to a specific websocket client
var targetConnection = connections[targetIndex]; targetConnection.send(data);
请注意,在实际项目中,代码实现可能会更加复杂。例如,您可能需要使用数据库来存储连接实例和相关数据,并且需要处理来自用户的错误数据或防范恶意攻击。因此,上述伪代码仅作为 WebSocket 实现的参考。