如何使用Java WebSocket API实现客户端和服务器端的通信?

发布于:2025-07-11 ⋅ 阅读:(19) ⋅ 点赞:(0)

WebSocket相关的方法主要涉及客户端和服务器端,以下是对其几个关键方法之间关联以及参数传递方式的介绍:

服务器端

Java中通常使用Jakarta WebSocket API(以前是Java EE的一部分,现在Jakarta EE 继续维护 )来实现WebSocket服务器端功能,常用注解有@ServerEndpoint, 关键方法包括:

  • onOpen(Session session):当客户端与服务器成功建立WebSocket连接时,该方法会被调用。
    • 方法关联:它是连接建立后的第一个触发方法,为后续的数据交互等操作做准备。通过它可以获取到代表该连接的 Session 对象,后续对连接的操作,如发送消息等,都依赖于这个 Session
    • 参数传递Session 参数由WebSocket容器在连接建立时自动创建并传递,它包含了与该连接相关的各种信息,如远程地址、请求头、发送消息的方法等。例如,你可以通过 session.getRemoteAddress() 获取客户端的远程地址。
  • onMessage(String message, Session session):当服务器接收到客户端发送的文本消息时会调用此方法(如果处理二进制消息,有对应的 onMessage(byte[] message, Session session) 方法 )。
    • 方法关联:它依赖于 onOpen 方法建立的连接,只有在连接成功建立后,才会接收并处理客户端发送的消息。在处理完消息后,也可以通过传入的 Session 对象向客户端发送响应消息。
    • 参数传递message 参数是客户端实际发送的文本内容,由WebSocket容器从网络传输数据中解析出来并传递。session 依然是代表该连接的会话对象,与 onOpen 方法中的 session 是同一个实例,用于在处理消息过程中操作连接,比如 session.getBasicRemote().sendText("Response message"); 向客户端发送响应文本消息。
  • onClose(Session session, CloseReason closeReason):当WebSocket连接关闭时调用,无论是正常关闭还是异常关闭。
    • 方法关联:它是连接生命周期的最后阶段,在连接关闭时触发,用于进行一些资源清理、状态更新等操作。
    • 参数传递session 是即将关闭的连接会话对象。closeReason 由WebSocket容器根据连接关闭的情况生成并传递,包含了关闭的状态码和关闭原因描述,比如 closeReason.getCloseCode().getCode() 可以获取关闭状态码,closeReason.getReasonPhrase() 获取关闭原因描述。
  • onError(Session session, Throwable throwable):当WebSocket连接在处理过程中发生错误时调用。
    • 方法关联:它与其他方法在异常情况下产生关联,一旦在消息处理、连接建立等过程中出现异常,就会触发此方法。可以在该方法中记录错误日志,根据情况关闭连接等。
    • 参数传递session 是出现错误的连接会话对象。throwable 是具体的异常对象,包含了异常类型和堆栈信息等,通过 throwable.printStackTrace() 可以打印出异常堆栈信息以便排查问题。

客户端

使用 StandardWebSocketClient 等类来实现WebSocket客户端功能,关键方法有:

  • connectToServer(Endpoint endpoint, URI uri):用于发起WebSocket连接。
    • 方法关联:它是客户端建立连接的入口方法,后续的消息接收、发送等操作都依赖于成功建立的连接。
    • 参数传递endpoint 是一个实现了 Endpoint 接口的类实例,包含了处理连接的回调方法,如 onOpenonMessage 等。uri 是要连接的WebSocket服务器的地址,格式为 ws://wss:// 开头。例如:
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
MyEndpoint myEndpoint = new MyEndpoint();
URI serverUri = new URI("ws://localhost:8080/your - websocket - path");
container.connectToServer(myEndpoint, serverUri);

其中 MyEndpoint 是自定义的实现了 Endpoint 接口的类。

  • sendText(String text)(在 Session 对象上调用 ):用于向服务器发送文本消息。
    • 方法关联:依赖于 connectToServer 方法成功建立的连接,只有在连接建立后才能发送消息。
    • 参数传递text 是要发送的文本内容,由客户端程序指定,然后通过WebSocket协议发送到服务器端。

通过这些方法的相互协作,实现了WebSocket的全双工通信功能,不同方法之间通过 Session 等对象以及参数传递来协同工作。


以下是基于该API的详细实现步骤,包含服务器端和客户端的代码示例及核心原理说明。

一、服务器端实现(核心步骤)

服务器端需要定义一个WebSocket端点(Endpoint),用于处理客户端的连接、消息接收、连接关闭等事件。主要通过注解或继承Endpoint类实现,推荐使用注解方式(更简洁)。

1. 依赖准备

若使用Maven,需添加Java EE WebSocket依赖(Java 7+支持,Java EE 7及以上内置):

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
    <scope>provided</scope> <!-- 容器(如Tomcat 8+)已内置,无需打包 -->
</dependency>
2. 定义WebSocket端点类

通过@ServerEndpoint注解标记端点,并指定访问路径(如/chat),同时实现核心事件方法:

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint("/chat") // 客户端连接的URL:ws://localhost:8080/项目名/chat
public class ChatServer {
    // 存储所有连接的客户端会话(线程安全集合)
    private static CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>();
    private Session session; // 当前客户端的会话

    /**
     * 客户端连接成功时触发
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        sessions.add(session); // 将新会话加入集合
        System.out.println("新客户端连接,当前在线:" + sessions.size());
    }

    /**
     * 收到客户端消息时触发
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        System.out.println("收到消息:" + message + "(来自会话:" + session.getId() + ")");
        // 广播消息给所有在线客户端
        for (Session s : sessions) {
            if (s.isOpen()) { // 确保会话未关闭
                s.getBasicRemote().sendText("服务器转发:" + message); // 同步发送消息
                // s.getAsyncRemote().sendText("异步发送:" + message); // 异步发送(非阻塞)
            }
        }
    }

    /**
     * 客户端连接关闭时触发
     */
    @OnClose
    public void onClose(Session session, CloseReason reason) {
        sessions.remove(session); // 从集合中移除会话
        System.out.println("客户端断开连接,原因:" + reason.getReasonPhrase() + ",当前在线:" + sessions.size());
    }

    /**
     * 通信发生错误时触发
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误:");
        error.printStackTrace();
    }
}

二、客户端实现(Java客户端)

Java客户端可通过WebSocketContainer创建连接,与服务器端通信。需注意:客户端API在Java EE中也有定义,或可使用第三方库(如Tyrus,JSR 356的参考实现)。

1. 客户端依赖(若需独立运行)

若使用Tyrus作为客户端(适合非Web容器环境),添加Maven依赖:

<dependency>
    <groupId>org.glassfish.tyrus.bundles</groupId>
    <artifactId>tyrus-standalone-client</artifactId>
    <version>1.17</version>
</dependency>
2. 客户端代码实现
import javax.websocket.*;
import java.net.URI;

@ClientEndpoint // 标记为客户端端点
public class ChatClient {
    private Session session; // 与服务器的会话

    /**
     * 连接服务器
     */
    public void connect(String serverUri) throws Exception {
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        container.connectToServer(this, new URI(serverUri)); // 连接到服务器端点
    }

    /**
     * 连接成功时触发
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        System.out.println("与服务器连接成功,会话ID:" + session.getId());
        try {
            session.getBasicRemote().sendText("客户端已连接"); // 向服务器发送消息
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 收到服务器消息时触发
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("收到服务器消息:" + message);
        // 可在此处处理消息(如回复、业务逻辑)
    }

    /**
     * 连接关闭时触发
     */
    @OnClose
    public void onClose(Session session, CloseReason reason) {
        System.out.println("与服务器断开连接,原因:" + reason.getReasonPhrase());
    }

    /**
     * 发生错误时触发
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("客户端错误:");
        error.printStackTrace();
    }

    /**
     * 向服务器发送消息
     */
    public void sendMessage(String message) throws IOException {
        if (session != null && session.isOpen()) {
            session.getBasicRemote().sendText(message);
        }
    }

    // 测试客户端
    public static void main(String[] args) throws Exception {
        ChatClient client = new ChatClient();
        client.connect("ws://localhost:8080/your-project/chat"); // 服务器端点URL
        // 模拟发送消息
        client.sendMessage("Hello, Server!");
        // 保持连接(实际应用中需根据业务处理)
        Thread.sleep(30000);
    }
}

三、核心概念与参数传递说明

  1. Session(会话)

    • 服务器端和客户端均通过Session对象标识一个连接,包含连接的元数据(如ID、是否打开)。
    • 消息发送通过SessiongetBasicRemote()(同步)或getAsyncRemote()(异步)实现。
  2. 消息传递

    • 服务器端@OnMessage方法接收客户端消息,参数message为消息内容(支持Stringbyte[]ByteBuffer等类型)。
    • 客户端通过ws.send()(JS)或session.getBasicRemote().sendText()(Java)发送消息,服务器端接收后可转发给其他客户端(如示例中的广播逻辑)。
  3. 生命周期方法关联

    • @OnOpen → 连接建立时触发,Session对象在此处初始化并加入管理集合。
    • @OnMessage → 依赖@OnOpen中初始化的Session进行消息转发。
    • @OnClose/@OnError → 清理Session资源,确保集合中只保留活跃连接。

四、部署与测试

  1. 服务器端部署到支持WebSocket的容器(如Tomcat 8+、Jetty 9+),启动后访问ws://localhost:8080/项目名/chat
  2. 运行Java客户端或浏览器客户端,输入消息即可实现双向通信。

网站公告

今日签到

点亮在社区的每一天
去签到