Закрытие сеанса websocket при остановке клиента - PullRequest
0 голосов
/ 04 декабря 2018

Я написал клиент Web Socket на Java, используя API клиента веб-сокета Jetty .У меня есть сомнения, когда я закрываю клиента, закрывается ли сеанс или нет.Сеанс может оставаться открытым, когда один пользователь / сторона сеанса веб-сокета останавливается и сообщения не отправляются с другой стороны.

Мой код:

Класс обслуживания Запуск веб-сокета:

public class WebSocketService {

    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketService.class);

    private int wsSessionTimeout ;

    public WebSocketService() {
        wsSessionTimeout = Integer.parseInt( AppPropertyLoader.getProperty(WEB_SOCKET_SESSION_TIMEOUT) );
    }

    public boolean checkResponse(String wsURL, String requestBody, List<String> responses)  {
        WebSocketClient client = new WebSocketClient();
        Websocket ws = (new Websocket.Builder()).addRequestToSendOnConnect(requestBody).addResponsesToCheck(responses).build() ;
        LOGGER.debug("WebSocket Objects: \n \n \t URL: {} , \n requestBody:{}, \n responses: {}", wsURL, requestBody, responses);
        boolean wasTestSuccessfull = false;
        try {
            URI url = new URI(wsURL);
            client.start();
            ClientUpgradeRequest request = new ClientUpgradeRequest();
            LOGGER.info("Connectiong to: "+ url);
            client.connect(ws,url,request);
            wasTestSuccessfull = ws.awaitClose(wsSessionTimeout);
        } catch (Exception e) {
            LOGGER.error("Error in web socket: {}", e);
        } finally {
            try {
                client.stop();  // wanted to check whether this call will also close the session.
            } catch (Exception e) {
                LOGGER.error("Error stopping jersey client: {}", e);
            }
        }
        return wasTestSuccessfull;
    }

}

Реализация класса Websocket:

@WebSocket(maxTextMessageSize = 64 * 1024)
public class Websocket{

    private final Logger LOGGER = LoggerFactory.getLogger(this.getClass().getCanonicalName());

    private String requestOnConnect;

    private Session session;

    private List<String> responses;

    int messageCount;

    private final CountDownLatch closeLatch;

    boolean isTestSuccessful;

    private int wsResponseTimeout;

    private static String SESSION_CLOSED = "Session Closed";

    public Websocket(Builder builder) {
        closeLatch = new CountDownLatch(1);
        this.requestOnConnect = builder.requestOnConnect;
        this.responses = builder.responses;
        messageCount = 0;
        wsResponseTimeout = Integer.parseInt( AppPropertyLoader.getProperty(WEB_SOCKET_RESPONSE_TIMEOUT) );
        isTestSuccessful = false;
    }


    public boolean awaitClose(int timeOutInSec) throws InterruptedException {   
        // closeLatch.await should always be first call as it is blocking and isTestSuccessful can be changed in between
        return this.closeLatch.await(timeOutInSec,TimeUnit.SECONDS) && isTestSuccessful ;
    }

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        LOGGER.info("Websocket Connection closed: "+statusCode+" "+reason);
        this.session = null;
        this.closeLatch.countDown(); // trigger latch
    }

    @OnWebSocketConnect
    public void onConnect(Session session) {
        LOGGER.info("Web socket connected.");
        this.session = session;     
        if(null != requestOnConnect) {
            Future<Void> future = session.getRemote().sendStringByFuture(requestOnConnect);
            try {
                future.get(wsResponseTimeout,TimeUnit.SECONDS);
                //TODO: use configurable value
            } catch (InterruptedException | ExecutionException | TimeoutException e) {  
                LOGGER.error("Websocket client is unable to send request: "+ e);
            }
        }
        if( responses == null || responses.size() == 0)
            session.close(StatusCode.NORMAL,SESSION_CLOSED);
    }

    @OnWebSocketMessage
    public void onMessage(String msg) {
        LOGGER.info("Websocket msg received: {}" ,  msg);
        if( msg.contains(responses.get(messageCount)) == false) {
            LOGGER.error("Websocket Received msg: \n {} is different from expected msg: {}", msg , responses.get(messageCount));
            LOGGER.info("Websocket Test Failure, Closing Session");
            session.close(StatusCode.BAD_PAYLOAD,"Session Closed");
        } else {
            messageCount++;
            if(messageCount == responses.size()) {
                LOGGER.info("Websocket Test Passed, Closing Session");
                isTestSuccessful = true;
                session.close(StatusCode.NORMAL,SESSION_CLOSED);
            }
        }
    }

    @OnWebSocketError
    public void onError(Throwable error) {
        LOGGER.error("WebSocket error : {}", error);
        session.close(StatusCode.NORMAL,SESSION_CLOSED);
    }

    // Used builder pattern to enforce immutability
    public static class Builder {

        private String requestOnConnect;

        private List<String> responses;

        // Used add Methods to make these parameters optional
        public Builder addRequestToSendOnConnect(String requestOnConnect) {
            this.requestOnConnect = requestOnConnect;
            return this;
        }

        public Builder addResponsesToCheck(List<String> responses) {
            this.responses = responses;
            return this;
        }

        public Websocket build() {
            return new Websocket(this);
        }

    }

    public String getRequestOnConnect() {
        return requestOnConnect;
    }

    public List<String> getResponses() {
        return responses;
    }

    public int getMessageCount() {
        return messageCount;
    }
}
...