I have a working server that's using sockets. My server-side code looks like this:
io.sockets.on('connection', function(socket) {
socket.emit('status', { counter: count });
});
In this example, I'm simply incrementing a counter by 1 every minute. When the counter updates, I'd like to send the current count to all clients. My index.html file looks like this:
<script>
var socket = io.connect('http://localhost');
socket.on('status', function (data) {
console.log(data);
});
</script>
When I start up my server, I can see the first data send to the client {'counter': 0}, however when the value of the counter increments, I don't see the new value being updated on the client. Why isn't new data being sent to my clients?
You emit the information only upon connection. For instance, if you just want to broadcast the information every minute - just change your code to:
io.sockets.on('connection', function(socket) {
setInterval(function() {
socket.emit('status', { counter: count });
}, 60 * 1000);
});
This will create an interval upon connection, and then emit the message every minute.
If you want something more advanced, such as listening to the change in count you need to subscribe to changes from it using a more advanced mechanism.
Update
Another way to achieve this is to emit on counter change (using the same function that updates it).
Yet another way is to use the experimental observe feature on a javascript object.
This question was already answered.
See: Update all clients using Socket.io?
The basic info is: you need to emit the message form the global socket io not the individual socket.
The socket.emit() only emits to one socket. Where as io.socket.emit() will emit the message to all sockets (broadcast message).
Related
I'm trying to develop an API for multiplayer online using socket programming in node js
I have some basic questions:
1. How to know which connection is related to a user?
2. How to create a socket object related to another person?
3. When it's opponent turn, how to make an event?
4. There is a limited time for move, how to handle the time to create an event and change turn?
As it is obvious I don't know how to handle users and for example list online users
If you can suggest some articles or answering these questions would be greate
Thanks
Keep some sort of data structure in memory where you are saving your sockets to. You may want to wrap the node.js socket in your own object which contains an id property. Then you can save these objects into a data structure saved in memory.
class User {
constructor(socket) {
this.socket = socket;
this.id = //some random id or even counter?
}
}
Then save this object in memory when you get a new socket.
const sockets = {}
server = net.createServer((socket) => {
const user = new User(socket);
sockets[user.id] = user
})
I am unsure what you mean by that, but maybe the above point helps out
This depends on when you define a new turn starts. Does the new turn start by something that is triggered by another user? If so use your solution to point 2 to relay that message to the related user and write something back to that socket.
Use a timeout. Maybe give your User class an additional property timeout whenver you want to start a new timeout do timeout = setTimeout(timeouthandler,howlong) If the timeouthandler is triggered the user is out of time, so write to the socket. Don't forget to cancel your timeouts if you need to.
Also, as a side note, if you are doing this with pure node.js tcp sockets you need to come up with some ad-hoc protocol. Here is why:
socket.on("data", (data) => {
//this could be triggered multiple times for a single socket.write() due to the streaming nature of tcp
})
You could do something like
class User {
constructor(socket) {
this.socket = socket;
this.id = //some random id or even counter?
socket.on("data", (data) => {
//on each message you get, find out the type of message
//which could be anything you define. Is it a login?
// End of turn?
// logout?
})
}
}
EDIT: This is not something that scales well. This is just to give you an idea on what can be done. Imagine for some reason you decide to have one node.js server instance running for hundreds of users. All those users socket instances would be stored in the servers memory
Currently, I'm testing my Node.js, Socket.io server on localhost and on devices connected to my router.
For testing purposes, I would like to simulate a delay in sending messages, so I know what it'll be like for users around the world.
Is there any effective way of doing this?
If it's the messages you send from the server that you want to delay, you can override the .emit() method on each new connection with one that adds a short delay. Here's one way of doing that on the server:
io.on('connection', function(socket) {
console.log("socket connected: ", socket.id);
// override the .emit() method
const emitFn = socket.emit
socket.emit = (...args) => setTimeout(() => {
emitFn.apply(socket, args)
}, 1000)
// rest of your connection handler here
});
Note, there is one caveat with this. If you pass an object or an array as the data for socket.emit(), you will see that this code does not make a copy of that data so the data will not be actually used until the data is sent (1 second from now). So, if the code doing the sending actually modifies that data before it is sent one second from now, that would likely create a problem. This could be fixed by making a copy of the incoming data, but I did not add that complexity here as it would not always be needed since it depends upon how the caller's code works.
An old but still popular question. :)
You can use either "iptables" or "tc" to simulate delays/dropped-packets. See the man page for "iptables" and look for 'statistic'. I suggest you make sure to specify the port or your ssh session will get affected.
Here are some good examples for "tc":
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem
I've a node.js (tcp) server, i.e.
net.createServer
And I've a node.js client. I've created a module.export with a method
this.connect = function() {
var client = new net.Socket();
client.setTimeout(5000);
client.connect(settings.collectorport, settings.collectorhost, function() {
console.log('connected');
});
....
And another method, like
this.write = function(data, client) {
client.write(some-string);
}
From another node.js file, I invoke such methods from inside a loop like:
while (something) {
agent.write(data,client);
}
What happens is that sometimes the server receives, or the client send, two "some-string" all togheter.
I mean, if in the server I log what the server is receiving, I see, sometimes only one "message", sometimes two or three "messages" merged.
What can it be?
Sorry for my lexicon...
Assuming the number of messages you are sending matches the number of messages you are receiving/expecting on the other end, then I think what you're describing is basically how TCP works.
TCP is a stream and so you can't/shouldn't make any assumptions about "message boundaries." You could receive one byte or 10 kilobytes at a time, it just depends on the networking stack and some other factors, so you should be prepared to handle any amount of data that comes in (e.g. create a protocol, perhaps using a delimiter character, to sort out individual "messages").
I almost wrote the question title as - Communicating between eventEmitters
I have a node.js module (X) that is on the global scope (it uses eventEmitter). I then have code that is local to each socket (user connected).
right now i am carrying X through the process on a global variable G={'X':X} so that the socket can then access X like this:
G.X.on('someEvent',doSomething);
This is dumb! Now every time i start my server it seems to act fine (I receive the event), but then if I refresh the page and emit an event I get it twice. If I refresh the page again I get the event 3 times.
I think that I am binding the listener to the same eventEmitter that is global.
How can I make a separate local eventListener to listen for the emits of the global eventEmiter?
I know how to set up an eventEmiter:
var events = require('events');
var ee = new events.EventEmitter();
ee.on('someEvent',function(){console.log('hello');});
but it does not catch the event of another...
I have also tried copying the module using the eventEmitter
var ee = G.X;
ee.on('someEvent',function() { console.log('hello'); });
But it still receives multiples of an event.
hello
hello
hello
This question was asked quite some time ago, but here's my answer anyways, seeing as there's no answer for it yet.
Listen to the socket object's "close" event, then remove the callbacks to your global. So it would look like:
X.addListener("someEvent", callback);
X.on("someEvent", function(socket){
socket.on("close", function(){
X.removeListener("someEvent", callback);
});
});
I need to run some function for every event from client in server node.js/socket.io
This is about calculate average time between events so I can detect spamers.
Any ideas? In docs I didn't find it. Something like:
socket.onAnyEvent( function() {
//do things
});
Here is a good thread: https://github.com/LearnBoost/socket.io/issues/434 specifically you can extend the emitter.