I'm trying to implement a simple lock using the following code:
Server:
socket.on('lock', function(ressInfo)
{
var lock = false;
if(ressLocks.indexOf(ressInfo.id) === -1)
{
ressLocks.push(ressInfo.id);
lock = true;
}
socket.emit("lock", lock);
});
Client:
this.requestLock = function(ressInfo, callback)
{
if(currentlyOnline)
{
socket.emit("lock", ressInfo);
socket.on("lock", function(lock)
{
// this gets triggered one additional time with each lock
callback(lock);
});
}
else
{
callback(true);
}
}
On the first call I get one callback with true, on the second call I get two callbacks with false, on the third call three, etc.
What is happening here? Why does socket.on get called multiple times?
I can think of two reasons:
Client side:
If you are registering for lock function multiple time
Server side:
As i assume this happens if you are registering multiple times to listen to the events assuming that you are running the socket.on function everytime you recieve events
Heres how you can debug.
Install node-debug
do node-debug "filename"
This will open in debug mode. Now check how many time the socket.on for 'lock' is being registered. I had similar issue. Heres how i solved it.
//check if msgtype is already binded
if (!isMessageTypeBinded(msgType, someKey)) {
// emit ot connection
io.of(someKey).emit(msgType, message)
return
} else {
// apply filter to all connection
var sockets = io.of(someKey).sockets
if (msgType) { // check for message tye
activeMsgConn.push({
"msgType": msgType,
"accessKey": someKey
})
for (index in sockets) {
var socket = sockets[index]
socket.on(msgType, notifyNewMsg(socket))
io.of(someKey).emit(msgType, message)
}
}
}
I am maintianing an array of all the connections made till now.
If a new msg comes, i'll first check if that msg was already binded to the socket and dont add any new namespace. Else i loop thorugh all the socket conneciton and add this handler.
In your case the code need not be same but implementation can be similar.
Related
I have got client and server socket.io code. Every message is being received except for one handler: when i send the following to the client:
socket.on('loginb', function(login) {
console.log(1);
var a = bedrijven.filter(function(e) {
return e.bedrijfsnaam == login.bnaam && e.pwd == login.pwd;
});
if (a[0] == null||a.length!=1||a==undefined) {
socket.emit('wow', false);
} else {
console.log(2,a);
socket.emit('wow', a[0]);
}
});
everything until "412" will be logged, but the message won't be received. This is how the listener looks at the client side:
socket.on('wow', function(login) {
console.log(26);
});
26 is never getting logged.
The strange thing is: the emitter and the listener are on the same place as other emitters and listeners i have, and work the same. However, this does not work while the rest does.
I also tried replacing socket.emit('wow', a[0]); by socket.emit('wow', 'string'); but no difference.
I found the answer thanks to #jfriend00's comment.
Indeed, the problem was that the client did not receive the socket message because the page refreshed after the submit. This was prevented by adding a return statement at the end of the submit function.
I'm trying to write an application that waits until there are two free users, then matches them together, in order to do this I am using the following function:
var gameManager;
io.on('connection', function(socket){
connected_users.push(socket.id);
console.log('user connected: ', socket.id);
if (connected_users.length >= 2) {
if (!gameManager) {
var gameManager = require('./scripts/gameManager.js')();
console.log('game started');
}
io.emit('initialize', gameManager.getFen());
}
console.log('appending event listener to user');
socket.on('move', function(move_json) {
console.log('move detected', move_json.player_id, gameManager)
if(!gameManager) {
return
}
// DO SOMETHING //
});
});
It seems to work fine, when the second user connects immediately both games initialize (I know that right now I'm emitting the initialize to all clients, this will be changed in the future), but then the 'move' emits from the first client always fail while the ones from the second work.
That is, suppose A connected first and then B, when A does the event that triggers an emit, the log line above shows
move detected [id of player A] undefined
while doing a move on board B gives
move detected [id of player B] GameManager {/* all the proterties*/}
Isn't it supposed to be the same exact object? why is the first socket unable to find it while the second is working as expected?
I'm working with HTML5 socket functions to establish a socket connection to my server. HTML5 has functions below to handle disconnecting
Socket.onclose = function()
{
...
}
Socket.onerror = function()
{
...
}
My problem is, how try for reconnect after onclose function executes? I tried to put a while loop inside of it like
ws.onclose = function()
{
While(conn==0)
{
ws = new WebSocket("ws://example.com");
}
}
and
ws.onopen = function()
{
conn=1;
...
}
But did't work.
Any idea?
Here's the script that comes with the Plezi websocket framework... It's fairly basic, but it works on the browsers I used it on (Safari, Chrome and FireFox).
The trick is to leverage the onclose method WITHOUT a loop.
The onclose method will be called even if the websocket never opened and the connection couldn't be established (without calling onopen).
Initiating a reconnect within an onclose is enough.
Writing a loop or a conditional review will not only fail, but will halt all the scripts on the page. Allow me to explain:
Javascript is single threaded. Again: it's an even/task based, single threaded, environment.
This means that your code acts like an atomic unit - nothing happens and nothing changes until your code finished running it's course.
Because connections could take a while to establish, the new WebSocket was designed (and rightfully so) as an asynchronous function.
This is how come you can define the onopen event callback AFTER the creation of the event.
The new websocket connection will be attempted only once the current task/event is finished...
...so a loop will get you stuck forever waiting for a task that can't be performed until your code stops running...
Back to the issue at hand, here's the code. If you have any ideas for improvements, please let me know:
// Your websocket URI should be an absolute path. The following sets the base URI.
// remember to update to the specific controller's path to your websocket URI.
var ws_controller_path = window.location.pathname; // change to '/controller/path'
var ws_uri = (window.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + window.document.location.host + ws_controller_path
// websocket variable.
var websocket = NaN
// count failed attempts
var websocket_fail_count = 0
// to limit failed reconnection attempts, set this to a number.
var websocket_fail_limit = NaN
// to offer more or less space between reconnection attempts, set this interval in miliseconds.
var websocket_reconnect_interval = 250
function init_websocket()
{
if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
websocket = new WebSocket(ws_uri);
websocket.onopen = function(e) {
// reset the count.
websocket_fail_count = 0
// what do you want to do now?
};
websocket.onclose = function(e) {
// If the websocket repeatedly you probably want to reopen the websocket if it closes
if(!isNaN(websocket_fail_limit) && websocket_fail_count >= websocket_fail_limit) {
// What to do if we can't reconnect so many times?
return
};
// you probably want to reopen the websocket if it closes.
if(isNaN(websocket_fail_limit) || (websocket_fail_count <= websocket_fail_limit) ) {
// update the count
websocket_fail_count += 1;
// try to reconect
setTimeout( init_websocket, websocket_reconnect_interval);
};
};
websocket.onerror = function(e) {
// update the count.
websocket_fail_count += 1
// what do you want to do now?
};
websocket.onmessage = function(e) {
// what do you want to do now?
console.log(e.data);
// to use JSON, use:
// var msg = JSON.parse(e.data); // remember to use JSON also in your Plezi controller.
};
}
// setup the websocket connection once the page is done loading
window.addEventListener("load", init_websocket, false);
I noticed that whenever my server is offline, and i switch it back online, it receives a ton of socket events, that have been fired while server was down. ( events that are ... by now outdated ).
Is there a way to stop socket.io from re-emitting the events after they have not received a response for x seconds ?.
When all else fails with open source libraries, you go study the code and see what you can figure out. After spending some time doing that with the socket.io source code...
The crux of the issue seems to be this code that is here in socket.emit():
if (this.connected) {
this.packet(packet);
} else {
this.sendBuffer.push(packet);
}
If the socket is not connected, all data sent via .emit() is buffered in the sendBuffer. Then, when the socket connects again, we see this:
Socket.prototype.onconnect = function(){
this.connected = true;
this.disconnected = false;
this.emit('connect');
this.emitBuffered();
};
Socket.prototype.emitBuffered = function(){
var i;
for (i = 0; i < this.receiveBuffer.length; i++) {
emit.apply(this, this.receiveBuffer[i]);
}
this.receiveBuffer = [];
for (i = 0; i < this.sendBuffer.length; i++) {
this.packet(this.sendBuffer[i]);
}
this.sendBuffer = [];
};
So, this fully explains why it buffers all data sent while the connection is down and then sends it all upon reconnect.
Now, as to how to prevent it from sending this buffered data, here's a theory that I will try to test later tonight when I have more time.
Two things look like they present an opportunity. The socket notifies of the connect event before it sends the buffered data and the sendBuffer is a public property of the socket. So, it looks like you can just do this in the client code (clear the buffer upon connect):
// clear previously buffered data when reconnecting
socket.on('connect', function() {
socket.sendBuffer = [];
});
I just tested it, and it works just fine. I have a client socket that sends an increasing counter message to the server every second. I take the server down for 5 seconds, then when I bring the server back up before adding this code, all the queued up messages arrive on the server. No counts are missed.
When, I then add the three lines of code above, any messages sent while the server is down are not sent to the server (technically, they are cleared from the send buffer before being sent). It works.
FYI, another possibility would be to just not call .emit() when the socket is not connected. So, you could just create your own function or method that would only try to .emit() when the socket is actually connected, thus nothing would ever get into the sendBuffer.
Socket.prototype.emitWhenConnected = function(msg, data) {
if (this.connected) {
return this.emit(msg, data);
} else {
// do nothing?
return this;
}
}
Or, more dangerously, you could override .emit() to make it work this way (not my recommendation).
Volatile events are events that will not be sent if the underlying connection is not ready (a bit like UDP, in terms of reliability).
https://socket.io/docs/v4/emitting-events/#volatile-events
socket.volatile.emit("hello", "might or might not be received");
I am trying to connect computer "a" to computer "b" using webrtc and print out the "Click" on computer "b" when the mouse is clicked on computer "a"'s canvas. I already created a working webrtc example where I make a connection between computer "a" and "b" and send messages between them using textboxes(chat).
I know to Attach a click event to the document. When the user clicks anywhere in the document, output "Click" will be displayed.
document.addEventListener("click", function(){
message.value= "Click!";
});
And these are some of the webrtc functions I have, I didnt post all my webRTC functions because I dont wanna make the question longer, it already is.
// a nice wrapper to send data
function send (room, key, data) {
roomRef.child(room).child(key).set(data);
}
// wrapper function to receive data
function recv (room, type, cb) {
roomRef.child(room).child(type).on("value", function (snapshot, key) {
var data = snapshot.val();
if (data) { cb(data); }
});
}
// get references to the document tags
var chatlog = document.getElementById("chatlog");
var message = document.getElementById("message");
function bindEvents () {
channel.onopen = function () { console.log("Channel Open"); }
channel.onmessage = function (e) {
// add the message to the chat log
chatlog.innerHTML += "<div>Peer says: " + e.data + "</div>";
};
}
// send a message the textbox throught
// the data channel for a chat program
function sendMessage () {
var msg = message.value;
channel.send(msg);
message.value = "";
}
My question is I dont know how to connect these two codes together or even if i did, I am not sure if it would work. So my question is how can I click on the canvas on computer "a" and get the textbox to print out "Click" on computer "b".
Thanks for reading
You could look into node.js and socket.io.
With these two you could connect multiple clients together and have a real-time communication between them. Other alternative is to use ajax with php, and make one browser to poll for new commands from server, and other browser to send them to server.
You're mostly there. What you can do is, after setting the message.value property, is call the sendMessage() function. This should trigger the application to send the correct value through the WebRTC Connection.