I write angularjs app and have some problem. My app use socket connection to get some data every time. For this reason i write factory(code below).
var Service = {};
var ws = new WebSocket("url");
var timer;
Service.onMessage = function(message) { /* some code */};
Service.onClose = function() {
timer = $interval(function () {
ws = new WebSocket("url");
Service.connect();
}, 1000);
};
Service.onOpen = function() {
console.log("open");
if (timer) $interval.cancel(timer);
};
Service.onError = function(error) { /* some code */};
Service.connect = function() {
// (Re)connect
// Reattaching handlers to object
ws.onmessage = Service.onMessage;
ws.onclose = Service.onClose;
ws.onopen = Service.onOpen;
ws.onerror = Service.onError;
}
return Service;
And what problem i have? For simplicity lats imagine that my server is down. And socket connection is down too. After that onclose event will start. But i dont understand how to re-connect with socket. I should check connection every 1 or 5 seconds, for example. In my code if socket closed, i create new socket object and try to connect anew. And what i have? When server is up, i have many-many objects which connect to socket. Please help me. How i can fixed this, for example, to have one object(one current connect)?
But i dont understand how to re-connect with socket. I should check
connection every 1 or 5 seconds
I think this is not a pure angular related question, here a general JavaScript answer (non tested):
function reconnect(url){
ws = new WebSocket(url);
}
ws.onclose = function(){
myTimeout = setTimeout(function(){reconnect('mywsURL')}, 5000);
};
In angular use:
var interval = $interval(your_callback, 5000);
and to cancel the timeout:
$interval.cancel(interval);
I suggest you to read the code of this lib, really interesting.
Related
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
I have an API in C# (asp.net) in which i'm running this websocket server using fleck:
SocketService.start();
SocketService.server.Start(socket =>
{
socket.OnOpen = () =>
{
SocketService.Connessione(socket);
};
socket.OnClose = () =>
{
SocketService.Disconnesione(socket);
};
socket.OnMessage = message =>
{
SocketService.Messaggio(message, socket);
};
});
This is SocketService.Start():
public static void start()
{
server = new WebSocketServer($"wss://{GetLocalIPAddress()}:{"4450"}/BNS/");
}
I have tried with a simple HTML/JS page using unsecure ws and it worked fine.
Then I have tried in my main program which i need it to be run on HTTPS so when using unsecure ws chrome told me to use wss instead.
So i change my ws server to wss but then it does nothing, it gives me timeout error.
This is the JS code:
var start = function () {
var wsImpl = window.WebSocket || window.MozWebSocket;
var form = document.getElementById('sendForm');
var input = document.getElementById('sendText');
alert("Connessione...");
// create a new websocket and connect
window.ws = new wsImpl('#Percorsi.IndirizzoSocket');
alert("conn");
// when the connection is established, this method is called
ws.onopen = function () {
alert("Connessione aperta");
var openJson = {
"Id": "#Model.accountCorrente.Id",
"type": "Identificazione"
};
alert("send");
ws.send(stringify(openJson));
};
// when the connection is closed, this method is called
ws.onclose = function () {
alert("Connessione chiusa");
}
// when data is comming from the server, this metod is called
ws.onmessage = function (val) {
if (confirm("Hai ricevuto un nuovo messaggio!\nPremi ok per visualizzarlo.")) {
window.location("/Annunci/Chat/" + val);
} else { }
};
}
I can't figured out how to make it works.
Thanks in advance for your help!
It seems like you are not setting the server certificate to be used under WS over TLS (not to be confused with HTTPS which is HTTP over TLS).
If you see the example in fleck's webpage, you will realize that you have to set the Certificate:
server.Certificate = new X509Certificate2("MyCert.pfx");
When I try to initialize a websocket connection to the server running on localhost with
var webSocket = new WebSocket("ws://localhost:8025/myContextRoot");
in javascript, but the server hasn't completed starting up yet, I get the error
SCRIPT12029: WebSocket Error: Network Error 12029, A connection with the server could not be established
How can I prevent this? I.e. how do I check if the server has already started or how can I force the WebSocket client to wait for the server?
What about:
var webSocketFactory = {
connectionTries: 3,
connect: function(url) {
var ws = new WebSocket(url);
ws.addEventListener("error", e => {
// readyState === 3 is CLOSED
if (e.target.readyState === 3) {
this.connectionTries--;
if (this.connectionTries > 0) {
setTimeout(() => this.connect(url), 5000);
} else {
throw new Error("Maximum number of connection trials has been reached");
}
}
});
}
};
var webSocket = webSocketFactory.connect("ws://localhost:8025/myContextRoot");
When you get a connection error, you can do a limited number of trial-errors to try to re-connect. Or you can endlessly try to reach the server.
The accepted answer is perfectly fine. I just would like to extend it a little bit further with promises.
var wsFactory = { tryCount: 3,
connect : function(url){
var ctx = this,
ws = new WebSocket(url);
return new Promise(function(v,x){
ws.onerror = e => { console.log(`WS connection attempt ${4-ctx.tryCount} -> Unsuccessful`);
e.target.readyState === 3 && --ctx.tryCount;
if (ctx.tryCount > 0) setTimeout(() => v(ctx.connect(url)), 1000);
else x(new Error("3 unsuccessfull connection attempts"));
};
ws.onopen = e => { console.log(`WS connection Status: ${e.target.readyState}`);
v(ws);
};
ws.onmessage = m => console.log(m.data);
});
}
};
wsFactory.connect("ws://localhost:8025/myContextRoot")
.then(ws => ws.send("Hey..! This is my first socket message"))
.catch(console.log);
You can't prevent (or put on hold) the WebSocket from starting / establish a connection. WebSocket automatically establishes a connection with the server when its declared. What you can do is place all your code inside onopen event handler that you want to execute on successful connection. So it would be like...
var webSocket = new WebSocket("ws://localhost:8025/myContextRoot");
webSocket.onopen = function() {
// code you want to execute
};
check this article to know more about WebSocket.
Hence the protocol can't get queried by the server if it is not started, the only option is trial and error.
Or you could let the WebSocket server create a simple textfile with the timestamp of the startup in your web space directory where the javascript can retrieve it and than try to establish a connection. You can retrieve the textfile with XMLHttpRequest.
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.
How to reconnect to socket io once disconnect has been called?
Here's the code
function initSocket(__bool){
if(__bool == true){
socket = io.connect('http://xxx.xxx.xxx.xxx:8081', {secure:false});
socket.on('connect', function(){console.log('connected')});
socket.on('disconnect', function (){console.log('disconnected')});
}else{
socket.disconnect();
socket = null;
}
}
If I do initSocket(true), it works. If I do initSocket(false), it disconnects. BUT THEN if I try to reconnect using initSocket(true), the connection does not work anymore. How can I get the connection to work?
Well, you have an option here ...
The first time you initialize the socket value you should connect with io.connect,
The next time ( after you've called disconnect once ), you should connect back with socket.socket.connect().
So your initSocket, should be something like
function initSocket(__bool){
if(__bool){
if ( !socket ) {
socket = io.connect('http://xxx.xxx.xxx.xxx:8081', {secure:false});
socket.on('connect', function(){console.log('connected')});
socket.on('disconnect', function (){console.log('disconnected')});
} else {
socket.socket.connect(); // Yep, socket.socket ( 2 times )
}
}else{
socket.disconnect();
// socket = null; <<< We don't need this anymore
}
}
I know you already have an answer, but I arrived here because the socket.IO client reconnection feature is broken in node at the moment.
Active bugs on the github repo show that lots of people aren't getting events on connect failure, and reconnect isn't happening automatically.
To work around this, you can create a manual reconnect loop as follows:
var socketClient = socketioClient.connect(socketHost)
var tryReconnect = function(){
if (socketClient.socket.connected === false &&
socketClient.socket.connecting === false) {
// use a connect() or reconnect() here if you want
socketClient.socket.connect()
}
}
var intervalID = setInterval(tryReconnect, 2000)
socketClient.on('connect', function () {
// once client connects, clear the reconnection interval function
clearInterval(intervalID)
//... do other stuff
})
You can reconnect by following client side config.
// 0.9 socket.io version
io.connect(SERVER_IP,{'force new connection':true });
// 1.0 socket.io version
io.connect(SERVER_IP,{'forceNew':true });
This is an old question, but I was struggling with this recently and stumbled here. Most recent versions of socket.io (>2.0) doesn't have the socket.socket property anymore as pointed out here.
I am using socket.io-client 2.2.0 and I was facing a situation where the socket seems to be connected (property socket.connected = true) but it wasn't communicating with the server.
So, to fix that, my solution was call socket.close()and socket.open. These commands force a disconnection and a new connection.
I had an issue with socket-io reconnect. May be this case will help someone. I had code like this:
var io = require('socket.io').listen(8080);
DB.connect(function () {
io.sockets.on('connection', function (socket) {
initSockets(socket);
});
});
this is wrong, becase there is a delay between open port assigned callbacks. Some of messages may be lost before DB gets initialized. The right way to fix it is:
var io = null;
DB.connect(function () {
io = require('socket.io').listen(8080);
io.sockets.on('connection', function (socket) {
console.log("On connection");
initSockets(socket);
});
});