springspring-bootspring-websocketjava-websocket

spring websocket client does not detect network connection loss


Spring @ClientEndpoint websocket client does not detect network disconnect due to cable unplug. I also have implemented a ping/pong mechanism. Can someone please help me out with what's going on? However I see following exception after reconnecting the cable, FYI, all setting are into default. Also I am connecting to a 3rd party remote endpoint where do not have any control.

xxxxxException: closed with code : CLOSED_ABNORMALLY reason: CloseReason: code [1006], reason [java.io.IOException: Connection reset by peer]
    at xxxxxx.onClose(WSClient.java:xx)

@ClientEndpoint
public class WSClient {
    private Session session;
    private int i = 0;

    @OnOpen
    public void open(Session session) {
        System.out.println("Connected to the server");
        this.session = session;
    }

    @OnClose
    public void close(Session session, CloseReason closeReason) {
        System.out.println("connection closed " + closeReason.getReasonPhrase());
    }

    @OnError
    public void error(Session session, Throwable t) {
        System.out.println(session.getId());
        System.out.println("Error in connection " + t.getMessage());
    }

    @OnMessage
    public void message(Session session, String message) {
        System.out.println("message received: " + message + " " + i++);
    }

    public void send(String message){
        try {
            if(session.isOpen()) {
                this.session.getBasicRemote().sendPing(ByteBuffer.wrap(message.getBytes()));
                System.out.println("socket is open " + i++);
            } else {
                System.out.println("socket closed");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@Component
public class ClientApp implements ApplicationListener<ApplicationReadyEvent> {

    private void startConnection() throws Exception {
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        WSClient client = new WSClient();
        container.connectToServer(client, new URI("ws://wshost:8080/ping"));

        while (true) {
            client.send("ping");
            TimeUnit.SECONDS.sleep(3);
        }
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        try {
            startConnection();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

Solution

  • This issue can be resolved by adding below code to WSClient.

    @OnMessage
    public void pongMessage(Session session, PongMessage msg) {
        LOGGER.debug("Pong message received: " + Instant.now());
        //schedule a timeout task, and raise an event or so if timed out.
    }
    

    The above snippet will be invoked when remote endpoint sends a pong message as a respond to the ping message sent. Basically there will be two methods annotated with @OnMessage, one to received the user message payload and another pong message payload sent by the framework.