安全问题: 由于WebSocket允许服务器主动向客户端发送数据,可能会存在安全问题。服务器必须保证只向合法的客户端发送数据。
let ws = new WebSocket('ws://example.com/ws');WebSocket.send() 方法: WebSocket.send() 方法用于向服务器发送数据。它接受一个参数,表示要发送的数据。数据可以是字符串、Blob 对象或 ArrayBuffer 对象。例如:
ws.send('Hello, server!');WebSocket.onopen 事件: WebSocket.onopen 事件在 WebSocket 连接成功建立时触发。例如:
ws.onopen = function() { console.log('WebSocket 连接已经建立。'); };WebSocket.onmessage 事件: WebSocket.onmessage 事件在接收到服务器发送的消息时触发。它的 event 对象包含一个 data 属性,表示接收到的数据。例如:
ws.onmessage = function(event) { console.log('收到服务器消息:', event.data); };WebSocket.onerror 事件: WebSocket.onerror 事件在 WebSocket 连接出现错误时触发。例如:
ws.onerror = function(event) { console.error('WebSocket 连接出现错误:', event); };WebSocket.onclose 事件: WebSocket.onclose 事件在 WebSocket 连接被关闭时触发。例如:
ws.onclose = function() { console.log('WebSocket 连接已经关闭。'); };以上是一些常用的 WebSocket API。
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> </dependency>3.1 使用Java WebSocket API编写WebSocket服务端
import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; // 堆代码 duidaima.com @ServerEndpoint("/echo") public class EchoServer { @OnOpen public void onOpen(Session session) { System.out.println("WebSocket 连接已经建立。"); } @OnMessage public void onMessage(String message, Session session) throws IOException { System.out.println("收到客户端消息:" + message); session.getBasicRemote().sendText("服务器收到消息:" + message); } @OnClose public void onClose() { System.out.println("WebSocket 连接已经关闭。"); } @OnError public void onError(Throwable t) { System.out.println("WebSocket 连接出现错误:" + t.getMessage()); } }这个示例代码定义了一个名为 "echo" 的 WebSocket 端点,它会监听客户端发来的消息,并将收到的消息返回给客户端。具体来说,它使用了 @ServerEndpoint 注解来指定 WebSocket 端点的 URL,使用了 @OnOpen、@OnMessage、@OnClose 和 @OnError 注解来定义 WebSocket 事件处理器。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>WebSocket Demo</title> <script> var ws = new WebSocket('ws://localhost:8080/echo'); ws.onopen = function() { console.log('WebSocket 连接已经建立。'); ws.send('Hello, server!'); }; ws.onmessage = function(event) { console.log('收到服务器消息:', event.data); }; ws.onerror = function(event) { console.error('WebSocket 连接出现错误:', event); }; ws.onclose = function() { console.log('WebSocket 连接已经关闭。'); }; </script> </head> <body> <h1>WebSocket Demo</h1> </body> </html>这个客户端使用了 WebSocket 构造函数来创建一个 WebSocket 对象,并指定连接的 URL 为我们之前部署的服务端的 URL。它使用了 WebSocket 的事件处理器来处理 WebSocket 事件,例如当 WebSocket 连接成功建立时,它会向服务器发送一条消息,并在收到服务器的响应时打印出消息内容。
import javax.websocket.*; import java.io.IOException; import java.net.URI; @ClientEndpoint public class EchoClient { private Session session; @OnOpen public void onOpen(Session session) { System.out.println("WebSocket 连接已经建立。"); this.session = session; } @OnMessage public void onMessage(String message, Session session) { System.out.println("收到服务器消息:" + message); } @OnClose public void onClose() { System.out.println("WebSocket 连接已经关闭。"); } @OnError public void onError(Throwable t) { System.out.println("WebSocket 连接出现错误:" + t.getMessage()); } public void connect(String url) throws Exception { WebSocketContainer container = ContainerProvider.getWebSocketContainer(); container.connectToServer(this, new URI(url)); } public void send(String message) throws IOException { session.getBasicRemote().sendText(message); } public void close() throws IOException { session.close(); } }3.3 使用Spring Boot编写WebSocket服务端
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>配置WebSocket
import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket") public class WebSocketServer { @OnOpen public void onOpen(Session session) { System.out.println("Connection opened: " + session.getId()); sessions.add(session); } @OnMessage public void onMessage(Session session, String message) throws IOException { System.out.println("Received message: " + message); session.getBasicRemote().sendText("Server received: " + message); } @OnClose public void onClose(Session session) { System.out.println("Connection closed: " + session.getId()); sessions.remove(session); } private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); }处理WebSocket消息
@OnMessage public void onMessage(Session session, String message) throws IOException { System.out.println("Received message: " + message); session.getBasicRemote().sendText("Server received: " + message); }在此代码中,我们简单地打印出收到的消息,并向客户端发送响应。
@OnClose public void onClose(Session session) { System.out.println("Connection closed: " + session.getId()); sessions.remove(session); }在此代码中,我们从连接池中删除连接,并打印出连接已关闭的消息。
import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new WebSocketServer(), "/websocket").setAllowedOrigins("*"); } }在此代码中,我们创建了一个新的WebSocketServer对象,并将其添加到WebSocket处理程序中。我们还指定了WebSocket端点(/websocket)和允许的来源(*)。
session.getBasicRemote().sendText("Hello, client!");二进制消息可以是任意类型的数据,包括图像、音频、视频等。要向客户端发送二进制消息,服务器可以使用Session对象的getBasicRemote()方法,将消息作为ByteBuffer对象发送。客户端可以使用WebSocket的send()方法来向服务器发送二进制消息。
byte[] data = // binary data ByteBuffer buffer = ByteBuffer.wrap(data); session.getBasicRemote().sendBinary(buffer);请注意,尽管文本消息和二进制消息在格式上有所不同,但它们都是通过WebSocket发送的消息类型,因此客户端和服务器都需要能够处理这两种类型的消息。
ByteBuffer pingMessage = ByteBuffer.wrap(new byte[] { 8, 9, 10 }); session.getBasicRemote().sendPing(pingMessage);要接收Pong消息,请在您的WebSocket处理程序中实现onPong()方法。当您的WebSocket服务器接收到Pong消息时,它将自动调用此方法,并将接收到的Pong消息作为ByteBuffer对象传递给它。
@OnMessage public void onPong(Session session, ByteBuffer pongMessage) { System.out.println("Received Pong message: " + pongMessage); }请注意,Ping和Pong消息通常用于WebSocket连接的健康检查。如果您希望在WebSocket连接中使用此功能,则应定期发送Ping消息并等待Pong消息的响应。
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Closing from client."));要处理接收到的关闭消息,请在您的WebSocket处理程序中实现onClose()方法。当您的WebSocket服务器接收到关闭消息时,它将自动调用此方法,并将接收到的状态码和关闭原因传递给它。
@OnClose public void onClose(Session session, CloseReason closeReason) { System.out.println("Connection closed: " + closeReason.getCloseCode() + " - " + closeReason.getReasonPhrase()); }请注意,客户端和服务器都应该发送关闭消息以结束WebSocket连接。如果只有一方发送了关闭消息,则另一方可能无法正确地关闭连接,并且可能需要等待超时才能释放资源。建议客户端和服务器在关闭连接时都发送关闭消息,以确保连接正确地关闭。
避免网络阻塞: WebSocket 的性能也会受到网络阻塞的影响。当有太多的连接同时请求数据时,服务器的性能会下降。使用合适的线程池和异步 IO 操作可以避免网络阻塞,提高 WebSocket 服务的并发性能。