WebSocket events not firing sporadically - javascript

I searched for a while but couldn't find a working solution for my particular problem.
I have the "default" WebSocket implementation in my JavaScript file. It works but it does not work everytime. Sometimes (can be the first time but could also be the 101st time) the event don't fire. Shouldn't at least the onclose-event fire with wasClean == false?
Maybe someone can help me out with this.
Edit: Forgot something. Only happens if I provide a wrong IP-Adress for:
ws = new WebSocket("ws://" + ip + ":9999/");
So server-side code is not necessary to answer this question.
$(document).ready(function () {
ws = new WebSocket("ws://" + ip + ":9999/");
ws.onopen = function(evt) {
console.log("CONNECTED");
doSend("getInfo");
};
ws.onclose = function(evt) {
if (!evt.wasClean) {
showError();
return;
}
console.log("DISCONNECTED");
};
ws.onmessage = function(evt) {
newIP = evt.data;
};
});

Solved it myself.
Problem was that the no-route-to-host error wasn't firing fast enough if there is no device behind the given IP-Adress. So I implemented a timeout which checks if the readyState of the socket is zero after 100 ms (Application runs in a Local Area Network so the time should be large enough)
function checkServer(ip, port) {
var ws = new WebSocket("ws://" + ip + ":" + port);
setTimeout(function() {
if (ws.readyState == 0) {
showError();
}
else {
ws.close();
ConnectToServer();
}
}, 100);
}

Related

Websocket won't reconnect unless I close the browser tab and restart it

I have a webserver with websockets set up on an ESP8266. The application runs fine on both client and server sides, sending and receiving data. However, if the server side disconnects (power cycle or upload new code), the client (Chrome) won't reconnect to the websocket. I can reload/refresh the web page, and it claims (according to the console log) to be connecting to the websocket, but it does not. The only solution I have found that works is to close the tab, and then restart a new session.
My code is heavily based on this tutorial from Random Nerd Tutorials
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
function initWebSocket() {
console.log('Trying to open a WebSocket connection...');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <-- add this line
}
function onOpen(event) {
console.log('Connection opened');
}
function onClose(event) {
console.log('Connection closed');
setTimeout(initWebSocket, 2000);
}
Is there something that is missing from the code above to make it more reliable?
You probably need to use setInterval. Try this, you may have to tweek it a bit.
var gateway = `ws://${window.location.hostname}/ws`;
var websocket, sockTimer=null;
function initWebSocket() {
console.log('Trying to open a WebSocket connection...');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onerror = onError; //  new
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <-- add this line
}
function onOpen(event) {
clearInterval(sockTimer) // <= better
console.log('Connection opened');
}
function onError() { // <= New
sockTimer = setInterval(init, 1000 * 60);
};
function onClose(event) {
console.log('Connection closed');
//setTimeout(initWebSocket, 2000);
sockTimer = setInterval(initWebSocket, 1000 * 60); // <=new
}

How can I do Ping/Pong between JavaScript and NodeJS WebSocket?

I'm currently developing a NodeJS WebSocket server. To detect broken connections I've followed this guide here:
https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
The server side works really good but the client makes problems because I can't find a ping function.
Does anyone has an idea how I can get the client part done without the library?
const WebSocket = require('ws');
function heartbeat() {
clearTimeout(this.pingTimeout);
// Use `WebSocket#terminate()`, which immediately destroys the connection,
// instead of `WebSocket#close()`, which waits for the close timer.
// Delay should be equal to the interval at which your server
// sends out pings plus a conservative assumption of the latency.
this.pingTimeout = setTimeout(() => {
this.terminate();
}, 30000 + 1000);
}
const client = new WebSocket('wss://echo.websocket.org/');
client.on('open', heartbeat);
client.on('ping', heartbeat);
client.on('close', function clear() {
clearTimeout(this.pingTimeout);
});
One main problem is that there is no ping method I think:
client.on('open') -> client.onopen available in JavaScript
client.on('close') -> client.onclose available in JavaScript
client.on('ping') -> How? Just how?
There is no Javascript API to send ping frames or receive pong frames. This is either supported by your browser, or not. There is also no API to enable, configure or detect whether the browser supports and is using ping/pong frames.
https://stackoverflow.com/a/10586583/7377682
Sad but true, in case of the ping frame, the API does not support it as mentioned in previous answers.
The most popular workaround is to listen to the close event and try to reconnect to the server using an interval.
This tutorial is easy to understand and contains most use-cases to begin with WS:
var ws = new WebSocket("ws://localhost:3000/ws");
let that = this; // cache the this
var connectInterval;
var check = () => {
const { ws } = this.state;
if (!ws || ws.readyState == WebSocket.CLOSED) this.connect(); //check if websocket instance is closed, if so call `connect` function.
};
// websocket onopen event listener
ws.onopen = () => {
console.log("connected websocket main component");
this.setState({ ws: ws });
that.timeout = 250; // reset timer to 250 on open of websocket connection
clearTimeout(connectInterval); // clear Interval on on open of websocket connection
};
// websocket onclose event listener
ws.onclose = e => {
console.log(
`Socket is closed. Reconnect will be attempted in ${Math.min(
10000 / 1000,
(that.timeout + that.timeout) / 1000
)} second.`,
e.reason
);
that.timeout = that.timeout + that.timeout; //increment retry interval
connectInterval = setTimeout(this.check, Math.min(10000, that.timeout)); //call check function after timeout
};
// websocket onerror event listener
ws.onerror = err => {
console.error(
"Socket encountered error: ",
err.message,
"Closing socket"
);
ws.close();
};
I think what you are look for on the client is onmessage:
client.onmessage = function (event) {
console.log(event.data);
}
All messages sent from the server can be listened to this way. See https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications

WebSocket Javascript client not receiving messages from server

I've got a Java web application deployed on a local GlassFish 4.1 server that implements WebSockets to inter-operate with the web client. I'm able to successfully execute client-to-server communication over the socket, but server-to-client communication doesn't work for some reason.
The Java code that sends messages to the client:
try
{
String msg = ServerClientInteropManager.toResponseJSON(response);
parentSession.getBasicRemote().sendText(msg);
FLAIRLogger.get().info("Sent response to client. Message: " + msg);
}
catch (IOException ex) {
FLAIRLogger.get().error("Couldn't send message to session " + parentSession.getid() + ". Exception - " + ex.getMessage());
}
The Javascript code:
pipeline_internal_onMessage = function(event)
{
var msg = JSON.parse(event.data);
console.log("Received message from server. Data: " + event.data);
};
function pipeline_init()
{
if (PIPELINE !== null || PIPELINE_CONNECTED === true)
{
console.log("Pipline already initialized");
return false;
}
else
{
var pipelineURI = "ws://" + document.location.host + document.location.pathname + "webranker";
console.log("Attempting to establish connection with WebSocket # " + pipelineURI);
if ('WebSocket' in window)
PIPELINE = new WebSocket(pipelineURI);
else if ('MozWebSocket' in window)
PIPELINE = new MozWebSocket(pipelineURI);
else
{
console.log("FATAL: No WebSockets support");
alert("This browser does not support WebSockets. Please upgrade to a newer version or switch to a browser that supports WebSockets.");
return false;
}
// the other event listeners get added here
PIPELINE.onMessage = pipeline_internal_onMessage;
PIPELINE_CONNECTED = true;
window.onbeforeunload = function() {
pipeline_deinit();
};
console.log("Pipeline initialized");
return true;
}
}
The onMessage function is never fired, even when the server successfully calls the sendText() method. Using the AsyncRemote yields the same results. The onError listeners on both ends don't report anything either. This is my first time working with sockets so I might be missing something elementary.
replace
PIPELINE.onMessage = pipeline_internal_onMessage
with
PIPELINE.onmessage = pipeline_internal_onMessage
Please refer here for more.

If Websocket connection can't be established do something else

I'm currently running into a problem you guys might be able to help me with..
I'm using websockets to connect to a custom server. Now i want to integrate a second Server IP if the first one isn't available.
How is it possible to detect, that the connection couldn't be made because the server isn't reachable? When I enter a wrong ws://url in my script, Chrome for example gives me the following error:
WebSocket connection to 'wss://1234/' failed: Error in connection establishment: net::ERR_NAME_NOT_RESOLVED
in Firefox it's something complete different. Do you guys of any method to catch this error with Javascript?
Basically when the ws:// url can't be reached, i want to change a variable with a different Server-IP and try it with this one again...
Thanks for your help!
It seems there's no way to catch the problem on instantiation, even though the magical JavaScript black box somehow seems to know the problem occurs on the new WebSocket.
To detect this error, use the following:
ws = new WebSocket(server);
ws.onerror = function (evt) {
if (ws.readyState == 3) {
//Connection closed.
}
}
thanks #orbitbot,
I'm using a framework called jwebsocket (jwebsocket.org). My Code is basically this:
serverstate = "0";
console.log(serverstate);
function logon() {
if(serverstate == "0") {
lURL = "wss://testurl-one:9797";
} else if (serverstate == "1") {
lURL = "wss://testurl-two:9797";
}
var gUsername = "user";
var lPassword = "pass";
console.log( "Connecting to " + lURL + " and console.logging in as '" + gUsername + "'..." );
var lRes = lWSC.logon( lURL, gUsername, lPassword, {
// OnOpen callback
OnOpen: function( aEvent ) {
console.log( "jWebSocket connection established." );
},
// OnMessage callback
OnMessage: function( aEvent, aToken ) {
var lDate = "";
if( aToken.date_val ) {
lDate = jws.tools.ISO2Date( aToken.date_val );
}
console.log( "jWebSocket '" + aToken.type + "' token received, full message: '" + aEvent.data + "' " + lDate + "" );
console.log(aToken);
}
},
// OnClose callback
OnClose: function( aEvent ) {
console.log( "Disconnected from Server" );
console.log("Using next server..");
serverstate = "1";
console.log(serverstate);
console.log("Trying to connect to next server");
logon();
},
// OnClose callback
OnError: function( aEvent ) {
console.log ("Some error appeared");
}
});
console.log( lWSC.resultToString( lRes ) );
}
Of course this would work so far. My Problem is that im using websockets to open a connection, get some information, and after that close the connection again.
since this code will always be fired if the server connection is closed (which in many cases i want to..) i can't use it like that...
any other ideas on this problem ?
I got it.. for everyone else who's interested:
When connection is made you receive a message from there server. So if the server is not available.. there'll be no message. So i just added a variable to the "OnMessage" Part.. and in the disconnect i check if a message was received. If not the server isn't there.. if yes, everything works fine..
Assuming your code is something like this,
var host = 'ws://a.real.websocket.url';
var socket = new WebSocket(host);
... you just need to surround the call to new WebSocket with a try/catch block, something like this
try {
var socket = new WebSocket(host);
} catch (e) {
// inspect e to understand why there was an error
// and connect to another url if necessary
}
That being said, it might be easier to work with a websockets library such as Socket.IO or SockJS (https://github.com/sockjs/sockjs-client), which then would change your reconnection code logic to whatever the libraries provide.

JS Websockets - still reconnecting until it's successful

I need to connect to websocket even if the first attemp is not successful. I need some loop.
Now I have:
ws = new WebSocket('ws://domain');
if(!ws) return;
ws.onopen = function() {
ws.send('getpayments '+ response );
}; ...
and I need do this until connect.
Please help me.
Not really a loop but recursive retries:
var retry_connecting = function(domain, clb) {
var ws = new WebSocket(domain);
ws.onerror = function() {
console.log('WS Error! Retrying...');
// let the client breath for 100 millis
setTimeout(function() {
retry_connecting(domain, clb);
}, 100);
};
ws.onopen = function() {
clb(ws);
};
};
and usage
retry_connecting('ws://domain', function(ws) {
console.log('We are connected!');
});
This code will try to connect ad infinitum. I don't recommend that. But I'm sure you'll be able to modify it to run only a finite number of times and then return an error after too many retries.

Categories