Chrome: Websocket closing tab closes all other connections in all other tabs - java

Here is my Java endpoint
#ServerEndpoint("/tweets")
public class TweetStreamServer {
private static final Logger LOGGER = LoggerFactory.getLogger(TweetStreamServer.class);
#OnMessage
public void tweets(final String message, final Session session) throws IOException, InterruptedException {
System.out.println("session id:" + session.getId() + ", search term: " + message);
final Client twitterClient = TwitterHoseBird.getInstance(message);
while (!session.getOpenSessions().isEmpty()) {
for (final Session s : session.getOpenSessions()) {
if (twitterClient.isDone()) {
System.out.println("Twitter Client Done, waiting ...");
}
s.getBasicRemote().sendText(TwitterHoseBird.getMsgQueue().take());
}
}
}
#OnClose
public void onClose(Session session, CloseReason reason) throws IOException {
LOGGER.warn("closing session: {}, remaining session: {}", session.getId(), session.getOpenSessions().size());
}
On Chrome, I do the following in 4 different tabs
var connection = new WebSocket('ws://127.0.0.1:8080/tweetstream-1.0-SNAPSHOT/tweets');
connection.onopen = function () {
connection.send('germany');
};
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
connection.onclose = function (e) {
console.log('closing session');
};
All the tabs then receive data from Twitter.
If I do connection.close(); on one of the tab, only that tab closes connection, but other 3 still receive the data.
However, if I close the tab, it closes connections in all other tabs by logging closing session
What is the issue here?
On server, when I close tab, I see log as
[0m[33m09:24:53,342 WARN [com.self.tweetstream.TweetStreamServer] (default task-16) closing session: tulDjtq4Lx8s1Zo3mA2mwX8B, remaining session: 1
How can I make other connections live, even if any tab is closed?

Related

Get an error after deploying war file of grails Websocket using jar library

Following code works fine in the development environment but not in production. I got stuck due to this. I have tried to deploy with tomcat v9.0.24 and Tomcat v8.5.32. In the development environment, tomcat v9.0.24 is working but the issue is with production.
org.apache.catalina.core.StandardContext.startInternal Error during ServletContainerInitializer processing javax.servlet.ServletException: java.lang.NoSuchMethodException:org.glassfish.tyrus.server.TyrusServerConfiguration.<init>()
grails-3.3.4 Gradle:
//*********** Websoket *************//
compile 'org.glassfish.tyrus:tyrus-server:1.13.1'
compile 'javax.websocket:javax.websocket-api:1.1'
compile 'org.glassfish.tyrus:tyrus-container-grizzly-server:1.13.1'
Websocket class
import grails.gorm.transactions.Transactional
import grails.util.Environment
import grails.util.Holders
import pawnshoprest.staff.User
import javax.websocket.*
import javax.websocket.server.ServerEndpoint
#ServerEndpoint(value = "/broadcast/{user_id}/{username}")
class WebSocketsService {
//**************** declare client ***************
private static Set<Session> clients = Collections.synchronizedSet(new HashSet<Session>());
#OnOpen
static void onOpen(Session session) {
System.out.println("Connected ... " + session.getId());
clients.add(session);
}
#OnMessage
static String onMessage(String message, Session session){
println("\n")
System.out.println("my Message: " + message);
synchronized(clients){
// Iterate over the connected sessions
// and broadcast the received message
for(Session client : clients){
//if (!client.equals(session)){
System.out.println("************** Session ID *******************");
System.out.println("sender: " + session.getId());
System.out.println("Reciever: " + client.getId());
//************ broadcast message **********************
if(!session.pathParameters.user_id.equals(client.pathParameters.user_id)){
println('message sent to ' + client.pathParameters.username)
client.getBasicRemote().sendText(message);
}
//}
}
}
//return message;
}
#OnClose
static void onClose(Session session, CloseReason closeReason) {
//******** Client Disconnect ****************
System.out.println("Disconnected ... " + session.getId());
clients.remove(session)
}
}
Bootstrap.groovy
class Bootstrap{
def init = { servletContext ->
Server server = new Server("${InetAddress.getLocalHost().getHostAddress()}", 8025, "/websockets", null, WebSocketsService);
try {
server.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
println('\n')
println('**************************** Socket running ****************************')
println("Please press a key to stop the server.");
println('\n')
reader.readLine();
} catch (Exception e) {
e.printStackTrace();
} finally {
println('\n')
println('**************************** Socket Has Been Stopped ****************************')
println('\n')
}
}
}

Vertx 3 - SockJS socket opening canceled

I created a new verticle that should response for HTTP requests and SockJS bridged events. Based on this question https://stackoverflow.com/questions/41516328 and vert.x manual https://vertx.io/docs/vertx-web/java/#_sockjs I created this piece of code:
Java:
#Override
public void start(Future<Void> startFuture) throws Exception {
startHttpServer(startFuture);
startSockJSHandler();
}
private void startHttpServer(Future<Void> startFuture) {
HttpServer server = vertx.createHttpServer(new HttpServerOptions());
server.requestHandler(req -> {
System.out.println("[" + new Date().toString() + "] Request #" + ++requestCount);
if (req.path().contains("http")) {
req.response().putHeader("Access-Control-Allow-Origin", "*").end("req_num: " + requestCount);
}
}).listen(8080, ar -> startFuture.handle(ar.mapEmpty()));
}
private void startSockJSHandler() {
Router router = Router.router(vertx);
SockJSHandlerOptions sockJSOptions = new SockJSHandlerOptions().setHeartbeatInterval(2000);
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, sockJSOptions);
BridgeOptions bridgeOptions = new BridgeOptions();
bridgeOptions.addInboundPermitted(new PermittedOptions().setAddressRegex(".*")).addOutboundPermitted(new PermittedOptions().setAddressRegex(".*"));
sockJSHandler.bridge(bridgeOptions, be -> {
System.out.println("BRIDGE EVENT: " + be.type().toString());
});
router.route("/eventbus/*").handler(sockJSHandler);
}
JavaScript eventbus client:
var sock = new SockJS('http://localhost:8080/eventbus/');
sock.onopen = function() {
console.log('open');
sock.send('test');
};
sock.onmessage = function(e) {
console.log('message', e.data);
sock.close();
};
sock.onclose = function() {
console.log('close');
};
HTTP request/response works fine, but SockJS events not. In web browser 'Network' module I see only one SockJS request (http://localhost:8080/eventbus/info). 8 seconds in 'pending' status, and after this time the status is changed to 'closed' (method onclose() is called at the end).
Did I do something wrong?
The HttpServer must delegate requests to the Router. Otherwise nothing happens. Usually, it is configured to delegate all requests to the Router.
server.requestHandler(router::accept).listen(8080);
See Basic Vert.x-Web concepts in the docs.

Websocket connection closed automatically?

I'm newbie to the web-socket programming...
I have the following JavaScript client code:
var connection = new WebSocket('ws://localhost:8080/OmegaThings/registerdevice');
connection.onopen = function () {
console.log("Socket has been opened state = " + connection.readyState);
connection.send('Ping'); // Send the message 'Ping' to the server
connection.send('Websocket client');
};
console.log("Socket has been opened state = " + connection.readyState);
connection.send('finish');
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
Java endpoint:
#ServerEndpoint("/registerdevice")
public class RegisterDeviceEndPoint
{
private static final Logger LOG = Logger.getLogger(RegisterDeviceEndPoint.class.getName());
#OnOpen
public void connectionOpened()
{
LOG.log(Level.INFO, "******************connection opened**************");
}
#OnMessage
public synchronized void processMessage(Session session, String message)
{
LOG.log(Level.INFO, "received message: {0}", message);
}
#OnClose
public void connectionClosed()
{
LOG.log(Level.INFO, "connection closed");
}
}
on the firefox console I got the following output:
"Socket has been opened state = 1"
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
"Socket has been opened state = 0"
on the GlassFish server log I got "ping" and "Websocket client", but the connection closed after onopen event exit(not sure), thus, the last word "finish" doesn't appear on the log and the error occurs.
I want to know if my code is correct?
What causes the error? javascript code, GlassFish server configuration or the java endpoint code?
Try to change the glassfish 8080 port, eg: 8887, or make sure Your antivirus/other application are not using port 80, I previously had experience where my server websocket was blocked by antivirus which using port 80.

Why websocket.send() depends on alert?

I use websockets and Glassfish. I call start() funcion on load page. When start function contains alert it sends the message to the server but when I don't put the alert it doesn't work. I can't figure out why.
java script
function start() {
alert('a'); //this alert
webSocket.send('start_server');
}
function onMessage(event) {
document.getElementById('messages').innerHTML
+= event.data;
}
server side
#OnMessage
public void onMessage(String message, Session session)
throws IOException, InterruptedException {
System.out.println("Message recieved");
session.getBasicRemote().sendText(message);
}
#OnOpen
public void onOpen() {
System.out.println("Client connected");
}
Where do you initialize the web-socket on the client side?
The alert suspends execution until you click ok - so i guess your order of execution is wrong (initialize the websocket before webSocket.send)
You may send data after the WebSocket#open event happend.
var connection = new WebSocket(...)
connection.onopen = function () {
connection.send('Ping');
};
Source: html5rocks

JavaEE Websocket: closing browser tab closes all sessions irrespective of browser

I have a websocket endpoint as
#ServerEndpoint("/tweets")
public class TweetStreamServer {
private static final Logger LOGGER = LoggerFactory.getLogger(TweetStreamServer.class);
#OnMessage
public void tweets(final String message, final Session session) throws IOException, InterruptedException {
System.out.println("session id:" + session.getId() + ", search term: " + message);
final Client twitterClient = TwitterHoseBird.getInstance(message);
while (!session.getOpenSessions().isEmpty()) {
for (final Session s : session.getOpenSessions()) {
if (twitterClient.isDone()) {
System.out.println("Twitter Client Done, waiting ...");
}
s.getBasicRemote().sendText(TwitterHoseBird.getMsgQueue().take());
}
}
}
}
I deploy this on WildFly 8.1.0 Final. Then I open multiple tabs on Chrome, Safari and run the following
var connection = new WebSocket('ws://127.0.0.1:8080/tweetstream-1.0-SNAPSHOT/tweets');
connection.onopen = function () {
connection.send('germany');
};
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
connection.onclose = function (e) {
console.log('closing session');
};
Then all the tabs start receiving data from server.
Then when I do connection.close(); on one of the tabs, only that connection breaks while all the other tabs are still receiving the data
But if I close one of the tabs (in any browser), all the sessions that were open in all the other tabs close session with closing session message
Question
- Is it not a valid use case that if user closes a tab in one browser, all the other tabs should still receive the data?
- Do you see any bug/issue with what I am doing?
- How can I fix this issue?
Thanks
Instead of using
s.getBasicRemote().sendText(TwitterHoseBird.getMsgQueue().take());
change it to
s.getAsyncRemote().sendText(TwitterHoseBird.getMsgQueue().take());
and everything else would just workout fine

Categories