我已使用Jetty's websocket client API用Java编写了 Web套接字客户端。我怀疑,当我关闭客户端时,会话是否关闭。当websocket会话的一个用户/一侧停止并且另一侧没有发送消息时,该会话可能保持打开状态。
我的代码:
服务类启动Websocket:
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;
}
}