WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
concurrentHashMap是一个支持高并发更新与查询的哈希表(基于HashMap)。
在保证安全的前提下,进行检索不需要锁定。与hashtable不同,该类不依赖于synchronization去保证线程操作的安全。
@Slf4j
@Component
@ServerEndpoint("/websocket/{sessionId}")
public class ProjectConsoleWs {
public static ProjectConsoleWs service = new ProjectConsoleWs();
/**
* 存放所有在线的客户端 [sessionId, session]
*/
private static final Map<String, Session> clients = new ConcurrentHashMap<>();
public void sendMessage(String sessionId, String message) {
if (!clients.containsKey(sessionId)) {
log.error("未找到指定客户端{}的websocket连接!", sessionId);
return;
}
this.onMessage(message, clients.get(sessionId));
log.info("准备向客户端程序{}发送消息:{}", sessionId, message);
}
@OnMessage
public void onMessage(String message, Session session) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("消息发送失败!", e);
}
}
@OnOpen
public void onOpen(@PathParam("sessionId") String sessionId, Session session) {
if (clients.containsKey(sessionId)) {
log.warn("客户端程序{}已有连接,无需建立连接", sessionId);
return;
}
session.setMaxIdleTimeout(0);
clients.put(sessionId, session);
log.info("客户端程序{}建立连接成功!------>当前在线人数为:{}", sessionId,getOnlineCount());
}
@OnClose
public void onClose(@PathParam("sessionId") String sessionId, Session session) {
if (!clients.containsKey(sessionId)) {
log.warn("客户端程序{}没有连接,无需断开连接", sessionId);
return;
}
clients.remove(sessionId);
log.info("客户端程序{}断开连接成功!------>当前在线人数为:{}", sessionId,getOnlineCount());
}
@OnError
public void onError(Session session, Throwable throwable) {
log.info("连接{}发生错误!", session.getId());
throwable.printStackTrace();
}
public boolean sessionIsOpen(String sessionId){
return clients.get(sessionId).isOpen();
}
public synchronized int getOnlineCount(){
return clients.size();
}
}
@Configuration
public class WebSocketConfig {
@Bean("serverEndpointExporter")
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}