java - 如何检查 Websocket 连接是否有效

标签 java websocket java-websocket

我有一个到服务器的 websocket 连接:

import javax.websocket.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

@ClientEndpoint
public class WebsocketExample {

    private Session userSession;

    private void connect() {

        try {
            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
            container.connectToServer(this, new URI("someaddress"));
        } catch (DeploymentException | URISyntaxException | IOException e) {
            e.printStackTrace();
        }
    }

    @OnOpen
    public void onOpen(Session userSession) {
        // Set the user session
        this.userSession = userSession;
        System.out.println("Open");
    }

    @OnClose
    public void onClose(Session userSession, CloseReason reason) {
        this.userSession = null;
        System.out.println("Close");
    }

    @OnMessage
    public void onMessage(String message) {
        // Do something with the message
        System.out.println(message);
    }
}

一段时间后,似乎我没有再从服务器收到任何消息,但没有调用 onClose 方法。

我想要一种计时器,如果我在过去五分钟内没有收到任何消息,至少会记录一个错误(并且最多尝试重新连接)。当我收到一条新消息时,计时器将被重置。

我该怎么做?

最佳答案

这是我做的。我通过 jetty 更改了 javax.websocket 并实现了一个 ping 调用:

import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.WebSocketClient;

import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@WebSocket
public class WebsocketExample {

    private Session userSession;
    private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

    private void connect() {
        try {
            SslContextFactory sslContextFactory = new SslContextFactory();
            WebSocketClient client = new WebSocketClient(sslContextFactory);
            client.start();
            client.connect(this, new URI("Someaddress"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnWebSocketConnect
    public void onOpen(Session userSession) {
        // Set the user session
        this.userSession = userSession;
        System.out.println("Open");

        executorService.scheduleAtFixedRate(() -> {
                    try {
                        String data = "Ping";
                        ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
                        userSession.getRemote().sendPing(payload);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                },
                5, 5, TimeUnit.MINUTES);
    }

    @OnWebSocketClose
    public void onClose(int code, String reason) {
        this.userSession = null;
        System.out.println("Close");
    }

    @OnWebSocketMessage
    public void onMessage(String message) {
        // Do something with the message
        System.out.println(message);
    }
}

编辑:这只是一个 ping 示例...我不知道是否所有服务器都应该通过 pong 来应答...

Edit2:这里是处理pong消息的方法。诀窍不是监听 String 消息,而是监听 Frame 消息:

@OnWebSocketFrame
@SuppressWarnings("unused")
public void onFrame(Frame pong) {
    if (pong instanceof PongFrame) {
        lastPong = Instant.now();
    }
}

为了管理服务器超时,我修改了计划任务如下:

scheduledFutures.add(executorService.scheduleAtFixedRate(() -> {
                    try {
                        String data = "Ping";
                        ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
                        userSession.getRemote().sendPing(payload);

                        if (lastPong != null
                                && Instant.now().getEpochSecond() - lastPong.getEpochSecond() > 60) {
                            userSession.close(1000, "Timeout manually closing dead connection.");
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                },
                10, 10, TimeUnit.SECONDS));

...并在onClose方法中处理重连

关于java - 如何检查 Websocket 连接是否有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50117284/

相关文章:

java spring 4 hibernate 5 两个实体管理器上下文错误

ios - Socket.io 与 iOS 上的屏幕关闭断开连接

java - 实现网络套接字

java - 编译器无法正确识别构造函数重写

java - 如何在 Java 中对 ArrayList 的 ArrayList 进行操作?

java - 如何编写找到两点之间最大距离的 O(n^2) 方法

websocket - 通过推送消息触发重新绘制 Wicket 口组件

node.js - Kubernetes 和 Socket.io 404 错误 - 在本地可以工作,但应用到 kubernetes 后就不行了

java - 如何使用构造函数参数初始化 WebSocket 端点

tomcat - 通过从 Java 客户端使用 Spring 4 实现的 WebSockets 连接到 Stomp