I have developed and Android application with is connecting to JAVA Web Socket and basically it is working very well. The issue is, that sometimes the client is disconnected but connection at the server side is appearing to be connected.
I try to investigate, when and why it happened but unfortunately i could not find the a specific scenario that cause to this problem.
I have thought to implement Ping/Pong messaging between server and all clients and in case that there is no answer from the clients is to closed the connection at the server side.
i can easily implement such my private mechanism but I have read around and I understand that Java and Android has an build in Ping/Pong messaging mechanism but i was not able to find any example of that.
Can anyway, provide a simple example how to implement Ping/Pong messaging functionality using the build in tools?
I have succeed to implement Ping/Pong functionality between EE JAVA WebSocket and android application. The server is sending Ping message to client every 5 min. if server does not got Pong message back within 5 second, the server is closing client connection.
here is my solution if someone will need it:
WebSocket side:
public class User {
public ScheduledExecutorService pingExecutorService;
public Timer disconnectTimer;
private Session userSession;
private String userName;
public User(Session userSession) {
this.userSession = userSession;
}
public Session getUserSession() {
return userSession;
}
public void setUserSession(Session userSession) {
this.userSession = userSession;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
@OnOpen
public void onOpen(Session session) {
User newUserConnection = new User(session);
connections.getConnections().put(session.getId(), newUserConnection);
schedulePingMessages(newUserConnection);
}
@OnClose
public void onClose(Session session) {
handleOnClose(session);
}
@OnMessage
public void onMessage(String message, Session session) {
messageHandler.handleMessage(message, session);
}
@OnMessage
public void onPong(PongMessage pongMessage, Session session) {
String sourceSessionId = session.getId();
User user = connections.getConnections().get(sourceSessionId);
user.disconnectTimer.cancel();
user.disconnectTimer.purge();
}
@OnError
public void onError(Throwable t) {
System.out.println(new Date() + "onError::" + t.getMessage());
t.printStackTrace();
}
private void schedulePingMessages(User newUserConnection) {
newUserConnection.pingExecutorService = Executors.newScheduledThreadPool(1);
newUserConnection.pingExecutorService.scheduleAtFixedRate(() -> {
scheduleDiconnection(newUserConnection);
try {
String data = "Ping";
ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
newUserConnection.getUserSession().getBasicRemote().sendPing(payload);
} catch (IOException e) {
e.printStackTrace();
}
}, 300, 300, TimeUnit.SECONDS);
}
private void scheduleDiconnection(User user) {
user.disconnectTimer = new Timer();
user.disconnectTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
user.getUserSession().close(new CloseReason(CloseCodes.UNEXPECTED_CONDITION," Client does not response"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 5000);
}
The android side just need to add the following override method:
@Override
public void onWebsocketPing(WebSocket conn, Framedata f) {
Log.i("ZCF","got Ping !");
super.onWebsocketPing(conn, f);
}