前言
WebSocket是一种在客户端和服务器之间建立持久性连接的通信协议,使得双向通信成为可能。在Java中,有多种方式可以实现WebSocket,这次,主要介绍javax.websocket、spring-boot-starter-websocket和Netty三种方式进行实现,这是第一篇,通过javax.websocket实现。请大家多多关注,多多支持。
本期websocket源码部分可以关注公众号:程序员的小黑板,发送websocket领取
一、javax.websocket
优点:
-
标准化:javax.websocket是Java EE 7的一部分,提供了WebSocket的官方规范,因此具有广泛的支持和稳定性。
-
内置支持:Java EE容器提供对WebSocket的原生支持,不需要引入额外的依赖。
劣势:
-
限制性:规范相对严格,有时可能会限制自定义实现的灵活性。
-
较为繁琐:在一些情况下,使用javax.websocket可能需要编写较多的代码
实现方式:
1.创建websocket服务
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
@ServerEndpoint("/websocket")
public class WebSocketEndpoint {
private static CopyOnWriteArrayList<Session> sessions = new CopyOnWriteArrayList<>();
private Thread heartbeatThread;
@OnOpen
public void onOpen(Session session) {
sessions.add(session);
System.out.println("WebSocket Opened: " + session.getId());
startHeartbeat(session); // 开始心跳
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("Message from " + session.getId() + ": " + message);
}
@OnClose
public void onClose(Session session) {
sessions.remove(session);
System.out.println("WebSocket Closed: " + session.getId());
stopHeartbeat(); // 停止心跳
}
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("WebSocket Error: " + session.getId());
throwable.printStackTrace();
}
// 发送心跳消息
private void sendHeartbeat(Session session) {
try {
session.getBasicRemote().sendText("heartbeat");
} catch (IOException e) {
e.printStackTrace();
}
}
// 开始心跳定时器
private void startHeartbeat(Session session) {
heartbeatThread = new Thread(() -> {
while (true) {
try {
Thread.sleep(5000); // 每5秒发送一次心跳
sendHeartbeat(session);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
});
heartbeatThread.start();
}
// 停止心跳定时器
private void stopHeartbeat() {
if (heartbeatThread != null && heartbeatThread.isAlive()) {
heartbeatThread.interrupt();
}
}
//发送信息方法
private void sendMessage(Session session) {
String message = "";
//发送文本消息
session.getAsyncRemote().sendText(message);
Object obj = null;
//发送对象消息,会尝试使用Encoder编码
session.getAsyncRemote().sendObject(obj);
}
}
CopyOnWriteArrayLis
t
是Java中的一个线程安全的List实现。与普通的ArrayList不同,它的特点是在对其进行修改(添加、修改、删除等操作)时,不直接修改原始列表,而是先复制一份新的列表进行修改,完成后再将新的列表赋值回原始引用。这个过程确保了在遍历这个列表的同时,不会抛出ConcurrentModificationException
异常,因为遍历过程中原始列表是不会发生改变的。
由于CopyOnWriteArrayList
在修改时会复制一份数据,所以在写入操作频繁的情况下,可能会消耗更多的内存和一定的性能开销。但在读取操作频繁而写入操作相对较少的场景下,它能够提供较好的读取性能和线程安全性。
2.新增websocket配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* webSocket配置开启websocket支持
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
3.前端测试代码
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Example</title>
<script>
let socket = new WebSocket("ws://localhost:8080/websocket");
let heartbeatInterval;
// 当 WebSocket 连接打开时执行
socket.onopen = function(event) {
console.log("WebSocket is open.");
startHeartbeat(); // 开始心跳
};
// 当收到消息时执行
socket.onmessage = function(event) {
console.log("Received message: " + event.data);
// 在此处理接收到的消息
};
// 发送心跳消息
function sendHeartbeat() {
console.log("Sending heartbeat...");
socket.send("heartbeat");
}
// 开始心跳定时器
function startHeartbeat() {
heartbeatInterval = setInterval(sendHeartbeat, 5000); // 每5秒发送一次心跳
}
// 当 WebSocket 连接关闭时执行
socket.onclose = function(event) {
console.log("WebSocket is closed.");
clearInterval(heartbeatInterval); // 清除心跳定时器
};
function sendMessage() {
let message = document.getElementById("message").value;
socket.send(message);
}
</script>
</head>
<body>
<input type="text" id="message" placeholder="Type a message..."> <!-- 输入框,用于输入消息 -->
<button onclick="sendMessage()">Send</button> <!-- 发送按钮,调用sendMessage函数发送消息 -->
</body>
</html>
4.效果展示
后端:
关注我,学习更多简单好理解的编程和架构知识!
下一篇主要讲解spring-boot-starter-websocket方式
关注我 不迷路
或者微信 添加公众号,发送websocket获取教程源码