Java 如何检查Websocket连接是否处于活动状态

Java 如何检查Websocket连接是否处于活动状态,java,websocket,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() {

我有到服务器的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示例。。。我不知道是否所有的服务器都应该通过电话应答

Edit2:以下是如何处理pong消息。诀窍不是监听字符串消息,而是帧消息:

@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方法处理重新连接

您应该通过实现一个心跳系统来解决这个问题,该系统的一方发送
ping
,另一方用
pong
应答。几乎每个websocket客户端和服务器(据我所知)都在内部支持此功能。这种乒乓球拍可以从两侧发送。我通常在服务器端实现它,因为我通常知道它比客户端有更好的生存机会(我的观点)。如果客户长时间不发送回pong,我知道连接已断开。在客户端,我检查了同样的情况:若服务器很长时间并没有发送ping消息,我知道连接已断开


如果ping/pong没有在您使用的库中实现(我认为javaxwebsocket有它),那么您可以为此制定自己的协议。

为什么不ping/pong呢<代码>注意:Ping帧可以用作keepalive,也可以用作验证远程端点是否仍有响应的手段有标准的方法吗?请阅读规范。这就是它的工作原理。看看您的websocket框架是如何实现它的,或者编写自己的。因为您没有详细说明websocket代码使用了什么,什么框架/库等等。。如果它是这个框架的一部分,我不能帮你谷歌。谢谢。我不拥有服务器,所以我不能在服务器端编写任何代码。当我从我的客户端向服务器发送ping消息时,我从未收到pong应答。但是,您会提供如何发送ping帧的代码吗?这在我上面的应答中。好的,我检查了应答。If
session.getBasicRemote().sendPing(null)不起作用,那么您只需联系后端团队并与他们进行检查即可