1. 概述
同样的接着之前的WebScoket,之前实现的是所有的接收者都能接收到,刚好最近写到了点对点通信的功能,就把WebScoket的点对点通信搞懂了。
2. 实现
2.1 关键
1
| websocket = new WebSocket("ws://localhost:8080/api/websocket/100");
|
这里是关键的,这里实现了注册一个websocket的sid为100的,点对点通信主要就是靠这个唯一标识的sid进行通信的,所以我们需要实现不同的多个sid进行发送消息。
2.2 实现
由于需要使用的点对点通信,直接在发送的时候指定发送给谁就行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public void sendMessage(String message) throws IOException { JSONObject jsonMessage = new JSONObject(); jsonMessage.put("sid", sid); jsonMessage.put("msg", message);
String jsonString = jsonMessage.toString(); log.info("推送 {} 的信息: {}", sid, jsonString); this.session.getBasicRemote().sendText(jsonString); } public static void sendInfo(String message, String targetUserId) throws IOException { boolean isSent = false; for (WebSocketServer item : webSocketSet) { if (item.sid.equals(targetUserId)) { item.sendMessage(message); isSent = true; break; } } if (!isSent) { log.warn("未找到目标用户 sid: {},消息未送达: {}", targetUserId, message); } }
|
3. 全部代码
WebSocketServer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| package com.example.scoket.util;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import jakarta.websocket.*; import jakarta.websocket.server.PathParam; import jakarta.websocket.server.ServerEndpoint; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;
import java.io.IOException; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger;
@Component @Slf4j @ServerEndpoint(value = "/api/websocket/{sid}") public class WebSocketServer {
private static final AtomicInteger onlineCount = new AtomicInteger(0); private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
private Session session; private String sid = "";
@OnOpen public void onOpen(Session session, @PathParam("sid") String sid) { this.session = session; this.sid = sid.trim(); webSocketSet.add(this); this.sid = sid; addOnlineCount(); try { sendMessage("{\"msg\":\"conn_success\"}"); log.info("有新窗口开始监听: {},当前在线人数为: {}", sid, getOnlineCount()); } catch (IOException e) { log.error("WebSocket IO Exception", e); } }
@OnClose public void onClose() { webSocketSet.remove(this); subOnlineCount(); log.info("释放的 sid 为: {}", sid); log.info("有一连接关闭!当前在线人数为 {}", getOnlineCount()); }
@OnMessage public void onMessage(String message, Session session) throws IOException { log.info("收到来自窗口 {} 的信息: {}", session.getId(), message); try { Map<String, String> requestMap = JSONUtil.toBean(message, Map.class); if (requestMap != null && !requestMap.isEmpty()) { String targetUserId = requestMap.get("to"); String msg = requestMap.get("msg"); if (targetUserId != null && msg != null) { sendInfo(msg, targetUserId); } else { log.warn("消息格式错误,缺少 'to' 或 'msg' 字段: {}", message); } } } catch (Exception e) { log.error("解析或处理消息时出错: {}", e.getMessage(), e); } }
@OnError public void onError(Session session, Throwable error) { log.error("发生错误: " + error.getMessage(), error); if (session.isOpen()) { try { session.close(); } catch (IOException e) { log.error("关闭会话时出错: {}", e.getMessage(), e); } } }
public void sendMessage(String message) throws IOException { JSONObject jsonMessage = new JSONObject(); jsonMessage.put("sid", sid); jsonMessage.put("msg", message);
String jsonString = jsonMessage.toString(); log.info("推送 {} 的信息: {}", sid, jsonString); this.session.getBasicRemote().sendText(jsonString); } public static void sendInfo(String message, String targetUserId) throws IOException { boolean isSent = false; for (WebSocketServer item : webSocketSet) { if (item.sid.equals(targetUserId)) { item.sendMessage(message); isSent = true; break; } } if (!isSent) { log.warn("未找到目标用户 sid: {},消息未送达: {}", targetUserId, message); } }
public static int getOnlineCount() { return onlineCount.get(); }
public static void addOnlineCount() { onlineCount.incrementAndGet(); }
public static void subOnlineCount() { onlineCount.decrementAndGet(); } }
|
WebSocketConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.example.scoket.util;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }
}
|
5. 项目结构

6. 页面结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>WebSocket Example</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> </head> <body> <div id="main" style="width: 1200px;"></div> Welcome<br/> <input id="text" type="text" /> <button onclick="send()">发送消息</button> <hr/> <button onclick="closeWebSocket()">关闭WebSocket连接</button> <button onclick="openWebSocket()">开启WebSocket连接</button> <hr/> <div id="message"></div>
<script type="text/javascript"> var websocket = null; var currentUserId = "2237023838"; var targetUserId = "123123"; function openWebSocket() { if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/api/websocket/"+currentUserId);
websocket.onopen = function() { setMessageInnerHTML("WebSocket连接成功"); };
websocket.onerror = function() { setMessageInnerHTML("WebSocket连接发生错误"); };
websocket.onmessage = function(event) { console.log(event.data); try { var data = JSON.parse(event.data); setMessageInnerHTML("接收:"+data.msg); } catch (e) { console.error("解析消息失败:", e); } };
websocket.onclose = function() { setMessageInnerHTML("WebSocket连接关闭"); };
} else { alert('当前浏览器不支持 WebSocket'); } }
function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; }
function closeWebSocket() { if (websocket) { websocket.close(); websocket = null; } }
function send() { var message = document.getElementById('text').value; if (message) { var jsonMessage = JSON.stringify({ to: targetUserId, msg: message }); if (websocket && websocket.readyState === WebSocket.OPEN) { websocket.send(jsonMessage); setMessageInnerHTML("发送: " + message); document.getElementById('text').value = ''; } else { alert("WebSocket连接未开启!"); } } else { alert("请输入消息!"); } } </script> </body> </html>
|
像这样再编写2个sid不一样的页面就可以,这里不做赘述
7. 实现截图

可以看到只有t2作为sid:123123的接收到了消息
