Dad72 Posted February 6, 2015 Share Posted February 6, 2015 It is regularly ask so I suggest that I use as server NodeJS + socket.IO. this therefore create a master server and workers according to the number of heart of the machine. This solution allows to distribute the load. Here is the Serveur.js var cluster = require('cluster'), _portSocket = 8080, _portRedis = 6379, _HostRedis = 'localhost'; if (cluster.isMaster) { var server = require('http').createServer(), socketIO = require('socket.io').listen(server), redis = require('socket.io-redis'); socketIO.adapter(redis({ host: _HostRedis, port: _portRedis })); var numberOfCPUs = require('os').cpus().length; for (var i = 0; i < numberOfCPUs; i++) { cluster.fork(); } cluster.on('fork', function(worker) { console.log('Travailleur %s créer', worker.id); }); cluster.on('online', function(worker) { console.log('Travailleur %s en ligne', worker.id); }); cluster.on('listening', function(worker, addr) { console.log('Travailleur %s écoute sur %s:%d', worker.id, addr.address, addr.port); }); cluster.on('disconnect', function(worker) { console.log('Travailleur %s déconnecter', worker.id); }); cluster.on('exit', function(worker, code, signal) { console.log('Travailleur %s mort (%s)', worker.id, signal || code); if (!worker.suicide) { console.log('Nouveau travailleur %s créer', worker.id); cluster.fork(); } }); } if (cluster.isWorker) { var http = require('http'); http.globalAgent.maxSockets = Infinity; var app = require('express')(), ent = require('ent'), fs = require('fs'), server = http.createServer(app).listen(_portSocket), socketIO = require('socket.io').listen(server), redis = require('socket.io-redis'); socketIO.adapter(redis({ host: _HostRedis, port: _portRedis })); app.get('/', function (req, res) { res.emitfile(__dirname + '/interface.php');}); socketIO.sockets.on('connection', function(socket, pseudo) { socket.setNoDelay(true); socket.on('nouveau_client', function(pseudo) { pseudo = ent.encode(pseudo); socket.pseudo = pseudo; try { socket.broadcast.to(socket.room).emit('nouveau_client', pseudo); } catch(e) { socket.to(socket.room).emit('nouveau_client', pseudo); } console.log('L\'utilisateur : '+socket.pseudo+' s\'est connecter'); }); socket.on('message', function(data) { socket.broadcast.to(socket.room).emit('dispatch', data); }); socket.on('exit', function(data) { socket.close();}); socket.on('room', function(newroom) { socket.room = newroom; socket.join(newroom); console.log('Le membre '+socket.pseudo+' a rejoint le domaine '+socket.room); socket.broadcast.to(socket.room).emit('dispatch', 'L\'utilisateur : '+socket.pseudo+' a rejoint le domaine : '+socket.room); }); }); } And to install Node: Quote sudo apt-get install wget or apt-get install wget wget http://nodejs.org/dist/v0.10.22/node-v0.10.22.tar.gz tar xfz node-v0.10.22.tar.gz cd node-v0.10.22 ./configure make make install and install Redis server: Quote sudo apt-get install redis-server and modules: Quote npm install cluster npm install express npm install ent npm install fs npm install socket.IO npm install socket.io-redis npm install forever -g (forever start server.js) = Run as a service nodejs The server runs. ------------------------Client: <head> <script type="text/javascript" src="http://localhost:8080/socket.io/socket.io.js"></script> </head> <body> <script> var socket = null; try { socket = io.connect(); console.log("socket: Ok!"); } catch(err) { console.error("Socket is out of service!"); } if(socket != null) { socket.emit('new_client', 'admin'); // use variable php (COOKIES, SESSION...) socket.on('message', function(data) { $('#zone_chat').prepend('' + data.pseudo + ': ' + data.message + '<br />'); }); socket.on('new_client', function(pseudo) { $('#zone_chat').prepend('<em>' + pseudo + ' a rejoint le chat !</em><br />'); }); socket.on('moveObjet', function(data) { mesh = scene.getMeshByName(data.name); mesh.position = new BABYLON.Vector3(data.position); mesh.rotation = new BABYLON.Vector3(data.rotation); }); } </script> </body> The client runs. Vousk-prod., bombe93, GameMonetize and 2 others 5 Quote Link to comment Share on other sites More sharing options...
jerome Posted February 7, 2015 Share Posted February 7, 2015 Waaow nice Socket.io is a really a good websocket library especialy server side.As it can manage xhr fallback if WS can't connect, it is very versatile.Sometimes too much as you would prefer never to fallback to xhr polling when coding a game and force WS connection : xhr are just http, so too much overhead for often no useful data transfered, browser Same Origin Policy limited (whereas you can have your web server and your websocket server under different domain names with WS), etcSo Socket.io client xhr features are unnecessery imo as the genuine HTML5 WS API is enough (only my opinion)Not that important if you really force Socket.io to use WS connexions only. I can't understand in your server side code where you implemented the game session notion.In other terms, if I code a script (not a part of your game, just a baddy script ) connecting your WS server and if I start to emit (after having sent a 'pseudo' message) many many 'moveObject messages, I will probably spam every connected player and make the game unplayable. Imho, the server code should check if any incoming message is to be treated or dropped.A kind of unpredictable pre-shared game session token should be given to each authorized client (players only), and they should sent it back to the server in each emited message. Then the server would filter : messages containing the token are legitimate, others are dropped (this token can be set in WS sub-protocol header, for instance)This is a http-session-like mechanism.Unless Socket.io abstracts this behavior and I don't know it. Other mechanisms like public/private keys with live encryption/decryption client and server sides are possible too, but so complex to handle they aren't probably worth it for just to protect you game for illegitimate incoming messages. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 7, 2015 Author Share Posted February 7, 2015 The client-side communication to send and receive :<script type="text/javascript" src="http://localhost:8080/socket.io/socket.io.js"></script>var socket = io.connect('http://localhost:8080'); // créer la session du joueur sur le serveur par un COOKIE créer et récupérer avec PHP et la créer ici sur le serveur : socket.set('pseudo', pseudo);socket.emit('nouveau_client', '<?php echo $_COOKIE['pseudo'];?>'); // Quand on reçoit un message, on l'insère dans la pagesocket.on('message', function(data) { $('#zone_chat').prepend('' + data.pseudo + ': ' + data.message + '<br />');}); // Quand un nouveau joueur entre sur le jeusocket.on('nouveau_client', function(pseudo) { $('#zone_chat').prepend('<em>' + pseudo + ' a rejoint le jeu !</em><br />');}); socket.on('moveObjet', function(data) { data.objet.position = new BABYLON.Vector3(data.position); data.objet.rotation = new BABYLON.Vector3(data.rotation);});for the secutity of message: ent.encode(message); socket.emit to send to the serverand socket.on to receive from the server to each client bombe93 and jerome 2 Quote Link to comment Share on other sites More sharing options...
jerome Posted February 7, 2015 Share Posted February 7, 2015 Cool !I can see you send some cookie to the server indeed. Right. But I still think your server code should filter messages and accept only authorized clients.Maybe is it already the case and I can't understand it reading the server side code : does the encode function manage the cookie value and drop the incoming message if the cookie is unknown ?BTW, your implementation is really nice imho because it's light, KISS and scalable. heuu don't we drift far away from BJS here ? shameless references, in french, about websockets if you need :http://jerome.bousquie.fr/ws_slides.pdfhttp://jerome.bousquie.fr/ws_article.pdf Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 7, 2015 Author Share Posted February 7, 2015 In fact I manage the client connection via PHP and SQL querying a database. if it connects it is a client authorized for me. I think Babylon should be able to handle the network. what would be the icing on the cake and would this engine (babylon) the best engine in the world WebGL. Maybe one day Ahiru 1 Quote Link to comment Share on other sites More sharing options...
jerome Posted February 7, 2015 Share Posted February 7, 2015 In fact I manage the client connection via PHP and SQL querying a database. if it connects it is a client authorized for me. But what if I don't authenticate via PHP ? Imagine I am a baddy just wanting to have your online game down because I'm jealous of your success :I just could code a tiny script on my laptop to connect directly to your websocket server. This script could then emit infinitly 'moveObject' messages to your game server program which will handle them as I were a legitimate authenticated player, nope ? This is the point I wanted to draw your attention to. I think your WS server lacks of some kind of game session filtering.Maybe am I wrong ? I just can see where you reject/drop illegitimate incoming messages. Except this small but important lack imho, your implementation seems really good and smart to me anyway .It seems to be designed to only one big simultaneous game session, doesn't it ? Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 7, 2015 Author Share Posted February 7, 2015 You have reasons, it may be missing the listed security in case the person arrives on the play. But to reach the game requires a connection, so I did not worry about that side secutity. but it can be done later if necessary. Basically I have an index page that allows connection and redirects to the game. at that time I record the client to the server. Then I can add later the player of banishment in case of bad user, but it is not yet integrated into the server. maybe I would edit this later here when I should be there. Yes, it's a pretty big game. An adventure MMORPG with a publisher to integrate that each player can create his own world and a social network integrated into the game world to share their creations with quests ... ambitious project, but I like challenges. jerome 1 Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 7, 2015 Author Share Posted February 7, 2015 I put a lot of comment in the code of server in English . Quote Link to comment Share on other sites More sharing options...
jerome Posted February 7, 2015 Share Posted February 7, 2015 Nice, really nice I strongly recommend you to have this incoming message filtering if you want your game to have a commercial use... or simply to avoid attacker pollution during game sessions. WS protocol does know nothing about application level session : the WS server will accept by default any incoming connection. Arrf, my job is to deploy server services and to set up their security. Internet is not a quite place : run a public server, it will be attacked in the first minute !That's why I focus on this, just to alert you on this very risk. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 7, 2015 Author Share Posted February 7, 2015 Ok, I'll see to add that when I would study the issue. Thank you for Jerome advice. Quote Link to comment Share on other sites More sharing options...
jerome Posted February 7, 2015 Share Posted February 7, 2015 De rien Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 8, 2015 Author Share Posted February 8, 2015 Updating the server. it seems that there have been changes since the update to 1.2 socket.IO set() and get() are now depreciate. before we could create a session variable on the server like this:socket.set ('pseudo', 'dad72'); but now it suffice to simply:socket.pseudo = 'dad72' Same for get () is now made directlyif (socket.pseudo) Quote Link to comment Share on other sites More sharing options...
bombe93 Posted February 9, 2015 Share Posted February 9, 2015 I have a problem: RedisStore = require('socket.io/lib/stores/redis'),redis = require('socket.io/node_modules/redis'); RedisStore does not exist. I installed redis but the path is "root/node_modules/redis". Why use the path socket.io? This is the right solution? (http://stackoverflow.com/questions/23952640/migrating-socket-io-from-0-9-x-to-1-x-problems-with-configuring-redisstore) --------------------Returns many times this error "WebSocket connection to 'ws://MyIp:8520/socket.io/?EIO=3&transport=websocket&sid=HsbslLeePELkFMehAAAA' failed: Connection closed before receiving a handshake response" (8520 is the port that i choose) Why? Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 9, 2015 Author Share Posted February 9, 2015 did you install redis-server and start this server redis else npm install socket.io-redis --save using socket.io path, you are at the root of the boot server (NodeJS) Quote Link to comment Share on other sites More sharing options...
bombe93 Posted February 9, 2015 Share Posted February 9, 2015 Yes i installed redis (sudo apt-get install redis-server). If i write redis-server in command line this is the response (http://s15.postimg.org/kjrj6zosr/image.png). The path "RedisStore = require('socket.io/lib/stores/redis')," gives me an error (http://s9.postimg.org/d9lam45n3/image.png). Therefore i installed "npm install socket.io-redis --save" and changed this code: RedisStore = require('socket.io/lib/stores/redis'), redis = require('socket.io/node_modules/redis'); in this:RedisStore = require('socket.io-redis'), redis = require('redis'); but gives me this error: " WebSocket connection to 'ws://MyIp:8520/socket.io/?EIO=3&transport=websocket&sid=raU53papomMA0BuCAAAA' failed: Connection closed before receiving a handshake response" MyIp isn't localhost but the ip of server to external access. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 9, 2015 Author Share Posted February 9, 2015 actually, it looks like the path is not the right socket.io/lib/stores/redis. You have to install socket.io?Sorry, I'm not an expert of NodeJS and socket.IO Quote Link to comment Share on other sites More sharing options...
jerome Posted February 9, 2015 Share Posted February 9, 2015 "Connection closed before receiving a handshake response"Seems your websocket server isn't running or isn't accessible from your client (proxies ? firewalls ?). The handshake is the first stage of the connection before upgrading http protocol to ws protocol.please have a look at this tl;dr academic article (french) : http://jerome.bousquie.fr/ws_article.pdf just read the very last annex page (english) to check if you are in the case of traversing proxies or firewalls and how to workaround Quote Link to comment Share on other sites More sharing options...
bombe93 Posted February 9, 2015 Share Posted February 9, 2015 Yes socket.io is installed. I checked if the port is open with the site (http://www.yougetsignal.com/tools/open-ports/) and it results open. Quote Link to comment Share on other sites More sharing options...
jerome Posted February 9, 2015 Share Posted February 9, 2015 if you are using Dad72 example, the port is 8080 on your server IP. Quote Link to comment Share on other sites More sharing options...
bombe93 Posted February 9, 2015 Share Posted February 9, 2015 Is not possible to another port? Quote Link to comment Share on other sites More sharing options...
jerome Posted February 9, 2015 Share Posted February 9, 2015 it's possible on the port number you want ... server = require('http').createServer(app).listen(8080),You just need to run your server as root if you want some port number lower than 1024 Quote Link to comment Share on other sites More sharing options...
bombe93 Posted February 9, 2015 Share Posted February 9, 2015 Ok, i run in 8520 port. I tried several times and it seems that sometimes connects and sometimes it fails. I can't understand what is the problem Quote Link to comment Share on other sites More sharing options...
jerome Posted February 9, 2015 Share Posted February 9, 2015 log file is the sysadmin's friend Quote Link to comment Share on other sites More sharing options...
Dad72 Posted February 9, 2015 Author Share Posted February 9, 2015 You have also modify the client listed port? <script type="text/javascript" src="http://localhost:8520/socket.io/socket.io.js"></script>var socket = io.connect('http://localhost:8520'); Quote Link to comment Share on other sites More sharing options...
bombe93 Posted February 9, 2015 Share Posted February 9, 2015 For example, even if I do not open the web page where run the ws command sometimes appears to me also "Connected to worker: 2". I believe that it should not do it if I do not open the page, right? --------------------------- Yes, but i always use not localhost but the ip of the server and the port like 40.50.60.20:8520is right? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.