杰瑞科技汇

websocket java客户端

核心概念

在开始之前,先明确几个关键点:

websocket java客户端-图1
(图片来源网络,侵删)
  1. WebSocket 协议:一种在单个 TCP 连接上进行全双工通信的协议,客户端和服务器可以随时相互推送数据。
  2. Java 内置 API (java-websocket):Java 标准库中没有直接包含 WebSocket 客户端,最常用、最标准的“准官方”实现是 TooTallNate/Java-WebSocket,它通常被认为是 Java WebSocket 的“内置”或“标准”选择。
  3. 异步 vs. 同步:WebSocket 通信本质上是异步的,数据到达时,会触发一个回调事件,而不是像普通 HTTP 请求那样阻塞线程等待响应。
  4. 连接生命周期:客户端需要处理连接的开启、消息接收、错误发生和连接关闭等事件。

使用 java-websocket (最常用、推荐)

这是最流行和成熟的 Java WebSocket 客户端库,它轻量级、稳定,并且是许多其他框架的基础。

添加 Maven 依赖

在你的 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.5.5</version> <!-- 建议使用最新版本 -->
</dependency>

创建一个简单的 WebSocket 客户端

下面是一个完整的、可运行的客户端示例,它连接到一个公共的 WebSocket 测试服务器(ws://echo.websocket.org),发送一条消息,并打印收到的响应。

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.net.URISyntaxException;
public class SimpleWebSocketClient {
    public static void main(String[] args) {
        try {
            // 创建一个 WebSocketClient 实例
            // 注意:URI 必须以 "ws://" (WebSocket) 或 "wss://" (WebSocket Secure) 开头
            WebSocketClient webSocketClient = new WebSocketClient(new URI("ws://echo.websocket.org")) {
                @Override
                public void onOpen(ServerHandshake handshakedata) {
                    System.out.println("连接已建立!");
                    // 连接成功后,可以发送消息
                    this.send("Hello, WebSocket Server!");
                }
                @Override
                public void onMessage(String message) {
                    // 收到服务器发来的消息
                    System.out.println("收到消息: " + message);
                }
                @Override
                public void onClose(int code, String reason, boolean remote) {
                    // 连接关闭时触发
                    // remote=true 表示是服务器关闭的连接,false 表示是客户端关闭的
                    System.out.println("连接已关闭! Code: " + code + ", Reason: " + reason);
                }
                @Override
                public void onError(Exception ex) {
                    // 发生错误时触发
                    System.err.println("发生错误:");
                    ex.printStackTrace();
                }
            };
            // 连接服务器
            webSocketClient.connect();
            // 为了保持程序运行,以便接收消息
            // 在真实应用中,你可能需要一个更健壮的生命周期管理
            try {
                Thread.sleep(10000); // 等待10秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 关闭连接
            System.out.println("主动关闭连接...");
            webSocketClient.close();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
}

代码解析

  • WebSocketClient: 这是核心类,你需要继承它并重写几个关键方法。
  • onOpen(ServerHandshake handshakedata): 当 WebSocket 连接成功建立时,此方法被调用,这是发送第一条消息的好地方。
  • onMessage(String message): 当从服务器接收到文本消息时,此方法被调用。message 参数就是服务器发送的内容。
  • onClose(int code, String reason, boolean remote): 当连接关闭时调用。code 是关闭状态码,reason 是关闭原因,remote 指示关闭是由客户端还是服务器发起的。
  • onError(Exception ex): 在连接或通信过程中发生错误时调用。
  • connect(): 异步方法,用于启动连接过程。
  • send(String message): 向服务器发送文本消息。
  • close(): 关闭 WebSocket 连接。

使用 Spring WebSocket (适用于 Spring 应用)

如果你的项目是基于 Spring Framework 的,那么使用 Spring 的 WebSocket 支持会是更自然、更集成的选择。

websocket java客户端-图2
(图片来源网络,侵删)

添加 Maven 依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>5.3.23</version> <!-- 使用与你的 Spring 版本兼容的最新版本 -->
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>5.3.23</version>
</dependency>

创建 WebSocket 客户端端点

Spring 提供了 @ClientEndpoint 注解来简化客户端的创建。

import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import javax.websocket.*;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.CountDownLatch;
@Component
@ClientEndpoint
public class SpringWebSocketClient {
    private Session session;
    private final CountDownLatch latch = new CountDownLatch(1);
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("连接已建立!");
        this.session = session;
        latch.countDown(); // 通知连接已建立
        try {
            // 发送消息
            session.getBasicRemote().sendText("Hello from Spring WebSocket Client!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("收到消息: " + message);
    }
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        System.out.println("连接已关闭! Reason: " + closeReason);
    }
    @OnError
    public void onError(Session session, Throwable throwable) {
        System.err.println("发生错误:");
        throwable.printStackTrace();
    }
    public void sendMessage(String message) throws IOException {
        if (this.session != null && this.session.isOpen()) {
            this.session.getBasicRemote().sendText(message);
        }
    }
    public void connect(String uri) throws Exception {
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        container.connectToServer(this, new URI(uri));
    }
    public void disconnect() throws IOException {
        if (this.session != null && this.session.isOpen()) {
            this.session.close();
        }
    }
    public static void main(String[] args) throws Exception {
        SpringWebSocketClient client = new SpringWebSocketClient();
        client.connect("ws://echo.websocket.org");
        // 等待连接建立
        client.latch.await();
        // 发送第二条消息
        client.sendMessage("This is the second message.");
        // 等待一段时间以便接收消息
        Thread.sleep(5000);
        // 关闭连接
        client.disconnect();
    }
}

代码解析

  • @ClientEndpoint: 将一个类标记为 WebSocket 客户端端点。
  • @OnOpen, @OnMessage, @OnClose, @OnError: 这些注解将方法与 WebSocket 生命周期事件关联起来,与 java-websocket 的回调方法类似。
  • Session: 代表一个 WebSocket 会话,用于发送消息和获取会话信息。
  • ContainerProvider.getWebSocketContainer().connectToServer(...): 这是启动连接的标准方式。
  • getBasicRemote().sendText(...): 用于发送文本消息。

使用 Tyrus (Java EE 标准)

Tyrus 是 Java WebSocket (JSR-356) 的参考实现,通常用在 Java EE (如 Jakarta EE) 或支持 Servlet 3.1+ 的容器中。

添加 Maven 依赖

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-client</artifactId>
    <version>2.1.3</version> <!-- 使用最新版本 -->
</dependency>
<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-container-grizzly</artifactId>
    <version>2.1.3</version>
</dependency>

创建客户端

Tyrus 的客户端 API 与 Spring 的 @ClientEndpoint 非常相似,因为它们都遵循 JSR-356 规范。

import javax.websocket.*;
import java.net.URI;
import java.util.concurrent.CountDownLatch;
@ClientEndpoint
public class TyrusWebSocketClient {
    private Session session;
    private final CountDownLatch latch = new CountDownLatch(1);
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Tyrus: 连接已建立!");
        this.session = session;
        latch.countDown();
        try {
            session.getBasicRemote().sendText("Hello from Tyrus Client!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("Tyrus: 收到消息: " + message);
    }
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        System.out.println("Tyrus: 连接已关闭! Reason: " + closeReason);
    }
    @OnError
    public void onError(Session session, Throwable throwable) {
        System.err.println("Tyrus: 发生错误:");
        throwable.printStackTrace();
    }
    public void sendMessage(String message) throws IOException {
        if (this.session != null && this.session.isOpen()) {
            this.session.getBasicRemote().sendText(message);
        }
    }
    public void connect(String uri) throws Exception {
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        container.connectToServer(this, new URI(uri));
    }
    public static void main(String[] args) throws Exception {
        TyrusWebSocketClient client = new TyrusWebSocketClient();
        client.connect("ws://echo.websocket.org");
        client.latch.await();
        client.sendMessage("This is a message from Tyrus.");
        Thread.sleep(5000);
        // Tyrus 没有显式的 disconnect 方法,关闭 session 即可
        if (client.session != null && client.session.isOpen()) {
            client.session.close();
        }
    }
}

总结与选择建议

特性 java-websocket (TooTallNate) Spring WebSocket Tyrus (JSR-356)
易用性 简单直接,继承即可 非常集成,与 Spring 生态无缝对接 标准规范,注解清晰
依赖 轻量级,单一库 需要 Spring 框架 需要 Tyrus 库和容器
适用场景 独立 Java 应用,小型项目 基于 Spring 的所有项目 Java EE/Jakarta EE 应用,遵循标准
功能 核心功能完备 提供与 Spring MVC 集成的高级功能 标准功能,兼容性好
推荐度 ⭐⭐⭐⭐⭐ (通用首选) ⭐⭐⭐⭐⭐ (Spring 项目首选) ⭐⭐⭐⭐ (标准项目首选)

如何选择?

websocket java客户端-图3
(图片来源网络,侵删)
  • 如果你只是想在 Java 程序里快速实现一个 WebSocket 客户端,并且不想引入庞大的框架,java-websocket 是你的最佳选择,它简单、高效、文档齐全。
  • 如果你的项目已经使用了 Spring Boot 或 Spring Framework,毫无疑问应该使用 Spring WebSocket,它能更好地与其他 Spring 组件(如 Security, MVC)集成,管理起来更方便。
  • 如果你正在开发一个 Java EE 应用,或者希望代码严格遵循 Java 标准,Tyrus 是一个很好的选择,它保证了代码的可移植性。

希望这份详细的指南能帮助你顺利地在 Java 中使用 WebSocket 客户端!

分享:
扫描分享到社交APP
上一篇
下一篇