I am using Azure Pub-Sub Service for Chatting module in a ReactApplication, I am creating this connection using Websocket.
let ws = new WebSocket(token.url);
ws.onmessage = (data) => {
//Messages Logic
}
when i am in other tabs, or in the sametab for longer time(more than 40-45 mins). I am not receiving messages, but when i refresh the page and websocket initialization code gets executed again and then i receive messages again. Any Suggestions?
Use this technique :
function connect() {
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
// subscribe to some channels
ws.send(JSON.stringify({
//.... some message the I must send when I connect ....
}));
};
ws.onclose = function(e) {
console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function() {
connect();
}, 1000);
};
Related
I have a simple client-side script like this:
function connect() {
const { contextBridge } = require('electron');
var ws = new WebSocket('ws://localhost:3000');
ws.onerror = (error) => {
console.error(`Lost connection to server. Reason: ${error.message}`);
console.error('Attempting to reconnect...');
ws.close();
}
ws.onclose = (e) => {
setTimeout({
connect();
}, 500);
}
ws.addEventListener('open', () => {
console.log('Connected to server!');
});
// Some other stuff to call functions via the browser console
const API = {
ws_isOpen: () => { return ws.readyState === ws.OPEN }
}
contextBridge.exposeInMainWorld('api', API);
function send_msg(msg) {
// Process some data...
ws.send(msg);
}
}
connect();
It works normally when the server is running and it's trying to connect, or when the server is rebooting and it's trying to connect for the first time, but not while it's connected. What I mean is that, if I were to suddenly shut the server down while the client is being connected to it, it attempts to try to reconnect as usual and the success message does pop up. However, if I type in window.api.ws_isOpen() in the browser console, it returns false. When I try to send a message, an error pops up saying something like Websocket is already in CLOSING or CLOSED stage. I tried changing the ws variable type to let and const but it doesn't work.
Turns out the answer is really simple. For some reason, when I put the ws variable outside the connect() function and modify it in the function, it works. I'm guessing it kinda re-declares/re-new the ws variable. It looks something like this:
var ws = null;
function connect() {
ws = new WebSocket('ws://localhost:3000');
// the exact same as above here....
}
connect();
After rebooting the server and letting it reconnect:
>> window.api.ws_isOpen()
true
I feel like I'm supposed to know how this works...
I'm fairly new to Javascript and am trying to wrap my head around async, promises, etc.
I have an application running a TCP API (non-HTTP) on the localhost. I'm building an Electron app to interact with this API. I need to send a single request to the API every second and retrieve a single JSON object it returns.
I'm able to do this successfully (for while) by running something like this:
const net = require('net');
function apiCall() {
if (running) {
setTimeout(() => {
// Send the request
request = '{"id":1,"jsonrpc":"2.0","method":"getdetails"}'
socketClient = net.connect({host:'localhost', port:8888}, () => {
socketClient.write(request + '\r\n');
});
// Listen for the response
var response;
socketClient.on('data', (data) => {
response = JSON.parse(data).result;
updateUI(response);
socketClient.end();
});
// On disconnect
socketClient.on('end', () => {
console.log('Disconnected from API');
});
apiCall();
}, refreshRate)
}
}
After running this for an extended amount of time, it appears that the API server is crashing:
Error: connect ECONNREFUSED 127.0.0.1:8888
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146)
Unfortunately, I have no control over the API server or its source code. I'd like some clarification on whether my client might be causing the API server to crash by sending requests this way.
Should I be opening and closing the connection for each request or keep it open and send requests only every second?
If I should be keeping the connection open, how can I do this, and do I need to worry about keep-alive?
It looks like that every time you call apiCall you are creating a new socket client and you are not removing the old socket client instances. This is a memory leak and it will cause the application to crash after running for some time
You can keep a running connection instead like below
const net = require("net");
const { once } = require("events");
let socketClient;
function apiCall() {
if (running) {
setTimeout(async () => {
const request = '{"id":1,"jsonrpc":"2.0","method":"getdetails"}';
// Create the socket client if it was not already created
if (!socketClient) {
socketClient = net.connect({ host: "localhost", port: 8888 });
// On disconnect
socketClient.on("end", () => {
console.log("Disconnected from API");
socketClient.destroy();
socketClient = null;
});
// Wait until connection is established
await once(socketClient, "connect");
}
// Send the request
socketClient.write(request + "\r\n");
// Listen for the response
const data = await once(socketClient, "data");
const response = JSON.parse(data).result;
updateUI(response);
apiCall();
}, refreshRate);
}
}
Thank you for taking the time to read my problem. A website's javascript I'm reverse engineering executes the following line:
this.socket = new WebSocket(o.host)
The line is buried in functions of other functions, etc. so I am not able to access it normally during runtime. I would like to use a Proxy object to "inject" code whenever new Websocket() is called in order to notify me of its creation and save it to a global variable I would prepare prior.
My greasemonkey script would look something like this:
var caught_socket; // prepare variable
handler = {
apply: function(target, thisArg, argumentsList) {
console.log("WebSocket was created!");
caught_socket = target;
}
}
WebSocket = new Proxy(WebSocket, handler);
This obviously does not work and I would be grateful for any help or demonstration of how Proxies actually work!
Use Proxy.construct() instead, it will execute when new is called.
// Create a new WebSocket proxy
WebSocket = new Proxy(WebSocket, {
construct: (target, args) => {
console.log('New WebSocket Instance!')
return new target(...args)
}
})
// Test the WebSocket proxy by connecting to a remote server
const ws = new WebSocket('wss://echo.websocket.org')
// Listen for an open connection
// Send a message to the connection
ws.addEventListener('open', () => {
console.log('Connection Open!')
ws.send('hello')
})
// Listen for messages from the remote server
ws.addEventListener('message', msg => console.log('Response:', msg.data))
If you add a second proxy both proxies execute:
// Create a new WebSocket proxy
WebSocket = new Proxy(WebSocket, {
construct: (target, args) => {
console.log('New WebSocket Instance!')
return new target(...args)
}
})
WebSocket = new Proxy(WebSocket, {
construct: (target, args) => {
console.log('New WebSocket Override!')
return new target(...args)
}
})
// Test the WebSocket proxy by connecting to a remote server
const ws = new WebSocket('wss://echo.websocket.org')
// Listen for an open connection
// Send a message to the connection
ws.addEventListener('open', () => {
console.log('Connection Open!')
ws.send('hello')
})
// Listen for messages from the remote server
ws.addEventListener('message', msg => console.log('Response:', msg.data))
You could even return a completely different class:
class MyCoolWebSocket {
addEventListener(event, callback) {
console.log('override event:', event)
}
}
// Create a new WebSocket proxy
WebSocket = new Proxy(WebSocket, {
construct: (target, args) => {
console.log('New WebSocket Instance!')
return new WebSocket(...args)
}
})
// Create a new WebSocket proxy
WebSocket = new Proxy(WebSocket, {
construct: (target, args) => {
console.log('Greasemonkey override!')
return new MyCoolWebSocket(...args)
}
})
// Test the WebSocket proxy by connecting to a remote server
const ws = new WebSocket('wss://echo.websocket.org')
// Listen for an open connection
// Send a message to the connection
ws.addEventListener('open', () => {
console.log('Connection Open!')
ws.send('hello')
})
// Listen for messages from the remote server
ws.addEventListener('message', msg => console.log('Response:', msg.data))
Here's my methods to open/close socket connection:
methods: {
connect () {
this.$socket.onopen = () => {
this.status = 'connected'
this.$socket.onmessage = ({data}) => {
this.$socket.send(this.message)
console.log({ event: "Recieved message", data })
}
}
this.$socket.onclose = (e) => {
console.log('Socket is closed. Reconnect will be attempted in 1 second.')
setTimeout(() => {
this.connect()
}, 1000)
}
},
disconnect () {
this.$socket.close()
this.status = 'disconnected'
}
}
I'm not using socket.io etc, just built in Websocket object.
When i manually call disconnect () method - it closes the connection as expected, but when i send message again - it says that connection is closed. Since i call connect () in a mounted, then it won't reconnect if i don't refresh the page.
I've tried using watcher:
watch: {
'$socket': 'connect'
}
But no effect. Is there a way to watch for websocket connection status? If it's closed - call connect (), if it's error'ed - call connect () to reconnect it.
Your connect() method does nothing to "reconnect" to the WebSocket server. So calling this.connect() simply rewrites your onopen handler.
You have to take the steps necessary to reconnect to the WebSocket server. The most excellent answer to this question does a great job of explaining a great structure for your code:
vue: emitting global events from websocket listener
Unfortunately, it doesn't answer your specific question. So I've forked the sandbox from that answer and added the modified code below that allows you to achieve your goal.
import Vue from "vue";
const url = "wss://echo.websocket.org";
let socket;
const emitter = new Vue({
methods: {
send(message) {
if (1 === socket.readyState) socket.send(message);
},
close() {
if (1 === socket.readyState) {
emitter.$emit("message", "Closing Socket.");
socket.close();
socket = null; // prevent memory leak
}
},
connect() {
socket = new WebSocket(url);
socket.onmessage = function(msg) {
emitter.$emit("message", msg.data);
};
socket.onerror = function(err) {
emitter.$emit("error", err);
};
emitter.$emit("message", "Openning Socket.");
}
}
});
emitter.connect();
export default emitter;
To see how this service is used, check out index.js in the running sample is here:
https://codesandbox.io/s/ry4993q654
You should check the close status code before reconnecting.
e.code === 1e3 || e.code === 1001 || e.code === 1005
I am learning on how to use websockets. I am returning data to the front-end from the server via normal ws.send but I would at the same time I would like to have a set interval time to ping the front-end to see if clints are still alive there.. This is the code I am using at the moment.
ws.on('connection', function connection(ws, req) {
ws.on('message', function incoming(message) {
return_data = message;
heart_beat = {status:"Accepted", currentTime:"2013-02-01T20:53:32.486Z", "heartbeatInterval":300}
ws.send(JSON.stringify(heart_beat));
const interval = setInterval(function ping() {
ws.clients.forEach(function each(ws) {
if (ws.isAlive === false) return ws.terminate();
ws.isAlive = false;
ws.ping('', false, true);
});
}, 300);
});
});
I want to just wait 300 seconds, if there is no response from the front-end I will terminate the websocket after the first heartbeat send by me
Here is my front-end code.
ws.onopen = function(){
console.log("Connected");
}
ws.onclose = function(){
console.log("Disconnected");
ws.send('Disconnected');
}
Whats happening now is that, when I close the browser in the front-end the server in the back-end is still pinging, if I console.log it.
You have to clear the Timeout with clearInterval
Here is a working example with uWebSocket :
'use strict';
const uws = require('uws');
const PORT = 3000
/*********************************************************************
* Server *
*********************************************************************/
var wsServer = new uws.Server({ 'port': PORT });
let nextId=1;
wsServer.on('connection', function(ws) {
console.log('connection !');
ws.id='cnx'+nextId++;
ws.on('message', function(mess){console.log('message : '+mess); });
ws.on('error', function(error) {
console.log('Cannot start server');
});
ws.on('close', function(code, message) {
console.log('Disconnection: ' + code + ', ' + message);
clearInterval(ws.timer);
});
ws.on('pong',function(mess) { console.log(ws.id+' receive a pong : '+mess); });
ws.timer=setInterval(function(){pingpong(ws);},1000);
});
function pingpong(ws) {
console.log(ws.id+' send a ping');
ws.ping('coucou',{},true);
} // end of pingpong
/*********************************************************************
* Client *
*********************************************************************/
var wsClient1 = createClient('client1');
var wsClient2 = createClient('client2');
function createClient(id) {
var client = new uws('ws://localhost:'+PORT);
client.id=id;
client.on('ping',function(mess){ console.log(this.id+' receive a ping : '+mess); } );
client.on('message',function(mess){ console.log(this.id+' receive a message : '+mess); } );
client.on('close',function(){ console.log(this.id+' closed'); } );
return client;
}
function closeClient(client) {
console.log('close '+client.id); client.close();
}
setTimeout(function(){ closeClient(wsClient1); closeClient(wsClient2); wsServer.close(); },2500);
output is :
connection !
connection !
cnx1 send a ping
cnx2 send a ping
client2 receive a ping : coucou
client1 receive a ping : coucou
cnx1 receive a pong : coucou
cnx2 receive a pong : coucou
cnx1 send a ping
cnx2 send a ping
client2 receive a ping : coucou
client1 receive a ping : coucou
cnx1 receive a pong : coucou
cnx2 receive a pong : coucou
close client1
close client2
client1 closed
client2 closed
Disconnection: 0,
Disconnection: 0,