2012-03-14 25 views
60

Soy bastante nuevo en node.js y me ha resultado bastante complicado separar un proyecto en varios archivos a medida que el proyecto crece de tamaño. Tenía un archivo grande antes del cual funcionaba como servidor de archivos y como servidor Socket.IO para un juego HTML5 multijugador. Lo ideal es separar el servidor de archivos, la lógica de socket.IO (leer la información de la red y escribirla en un búfer con una marca de tiempo y luego emitirla a todos los demás jugadores) y la lógica del juego.Separación del servidor de archivos y la lógica socket.io en node.js

Usando el primer ejemplo de socket.io para demostrar mi problema, normalmente hay dos archivos. app.js es el servidor y index.html se envía al cliente.

app.js:

var app = require('http').createServer(handler) 
    , io = require('socket.io').listen(app) 
    , fs = require('fs') 

app.listen(80); 

function handler (req, res) { 
    fs.readFile(__dirname + '/index.html', 
    function (err, data) { 
    if (err) { 
     res.writeHead(500); 
     return res.end('Error loading index.html'); 
    } 

    res.writeHead(200); 
    res.end(data); 
    }); 
} 

io.sockets.on('connection', function (socket) { 
    socket.emit('news', { hello: 'world' }); 
    socket.on('my other event', function (data) { 
    console.log(data); 
    }); 
}); 

index.html:

<script src="/socket.io/socket.io.js"></script> 
<script> 
    var socket = io.connect('http://localhost'); 
    socket.on('news', function (data) { 
    console.log(data); 
    socket.emit('my other event', { my: 'data' }); 
    }); 
</script> 

Para servidor de archivos independiente y la lógica de servidor de juegos que necesitaría la función "manejador" se define en un archivo, necesitaría la función anónima usó una devolución de llamada para que io.sockets.on() estuviera en otro archivo, y necesitaría un tercer archivo para incluir ambos archivos correctamente. Por ahora he probado los siguientes:

start.js:

var fileserver = require('./fileserver.js').start() 
    , gameserver = require('./gameserver.js').start(fileserver); 

fileserver.js:

var app = require('http').createServer(handler), 
    fs = require('fs'); 

function handler (req, res) { 
    fs.readFile(__dirname + '/index.html', 
    function (err, data) { 
    if (err) { 
     res.writeHead(500); 
     return res.end('Error loading index.html'); 
    } 

    res.writeHead(200); 
    res.end(data); 
    }); 
} 

module.exports = { 
    start: function() { 
     app.listen(80); 
     return app; 
    } 
} 

gameserver:

var io = require('socket.io'); 

function handler(socket) { 
    socket.emit('news', { hello: 'world' }); 
    socket.on('my other event', function (data) { 
     console.log(data); 
    }); 
} 

module.exports = { 

    start: function(fileserver) {  
     io.listen(fileserver).on('connection', handler); 
    } 

} 

Esto parece funcionar (la estática el contenido se sirve correctamente y la consola muestra claramente un apretón de manos con Socket.IO cuando el cliente se conecta) aunque no hay datos Alguna vez enviado Es como si nunca se llamaran realmente socket.emit() y socket.on(). Incluso modifiqué el controlador() en gameserver.js para agregar console.log('User connected');, pero esto nunca se muestra.

¿Cómo puedo tener Socket.IO en un archivo, un servidor de archivos en otro, y todavía espero que ambos funcionen correctamente?

+4

¿conoces el marco express js? http://expressjs.com/ es genial y realmente te ayuda a estructurar tu aplicación. hay un montón de ejemplos en github (https://github.com/visionmedia/express/tree/master/examples) tal vez haya algo que pueda ayudarlo con su problema ... – pkyeck

+1

@pkyeck: Estoy leyendo en Ahora me expreso para tratar de descubrir cómo puede beneficiarme, pero hasta ahora parece más complicado de lo que necesito. Todo lo que realmente quiero es separar mi lógica para el servidor del juego y el servidor de archivos en dos archivos separados, luego tengo un tercer archivo que inicia correctamente ambos servidores. – stevendesu

+0

¿tuviste el tiempo de verificar mi "nueva" respuesta? – pkyeck

Respuesta

74

En socket.io 0.8, se debe adjuntar eventos utilizando io.sockets.on('...'), a menos que estés usando espacios de nombres, parece que falta la parte sockets:

io.listen(fileserver).sockets.on('connection', handler) 

Es probablemente mejor para evitar el encadenamiento de esa manera (es posible que desee utilizar el objeto io luego). La forma en que estoy haciendo esto ahora:

// sockets.js 
var socketio = require('socket.io') 

module.exports.listen = function(app){ 
    io = socketio.listen(app) 

    users = io.of('/users') 
    users.on('connection', function(socket){ 
     socket.on ... 
    }) 

    return io 
} 

A continuación, después de crear el servidor app:

// main.js 
var io = require('./lib/sockets').listen(app) 
+1

Gran respuesta, tratando de portar esto a krakenJS, pero el módulo socket.io nunca comienza:/ – Ms01

+1

No estamos usando 'return io' ¿no? es solo para la vario. – Sobiaholic

+0

¿Si deseo activar una solicitud de emisión? por ejemplo, 'app.get ('/ some/url', function (req, res) {// Quiero emitir aquí})' –

5

haría algo como esto.

app.js

var app = require('http').createServer(handler), 
    sockets = require('./sockets'), 
    fs = require('fs'); 

function handler (req, res) { 
    fs.readFile(__dirname + '/index.html', 
    function (err, data) { 
    if (err) { 
     res.writeHead(500); 
     return res.end('Error loading index.html'); 
    } 

    res.writeHead(200); 
    res.end(data); 
    }); 
} 

sockets.startSocketServer(app); 
app.listen(80); 

y sockets.js

var socketio = require('socket.io'), 
     io, clients = {}; 

module.exports = { 

     startSocketServer: function (app) { 
       io = socketio.listen(app); 

       // configure 
       io.configure('development', function() { 
         //io.set('transports', ['websocket', 'xhr-polling']); 
         //io.enable('log'); 
       }); 

       io.configure('production', function() { 
         io.enable('browser client minification'); // send minified client 
         io.enable('browser client etag');   // apply etag caching logic based on version number 
         io.set('log level', 1);     // reduce logging 
         io.set('transports', [      // enable all transports (optional if you want flashsocket) 
          'websocket' 
          , 'flashsocket' 
          , 'htmlfile' 
          , 'xhr-polling' 
          , 'jsonp-polling' 
         ]); 
       }); 
       // 

       io.sockets.on('connection', function (socket) { 
         console.log("new connection: " + socket.id); 

         socket.on('disconnect', function() { 
           console.log("device disconnected"); 

         }); 

         socket.on('connect_device', function (data, fn) { 
           console.log("data from connected device: " + data); 
           for (var col in data) { 
             console.log(col + " => " + data[col]); 
           } 


         }); 
       }); 
     } 
}; 

Puedo copiar & pegado algo de mi antiguo código - no saben realmente lo que ha cambiado en las últimas versiones de zócalo. io, pero esto es más sobre la estructura que el código real.

y sólo lo usaría 2 archivos para sus propósitos, no 3. cuando se piensa en dividirlo aún más, tal vez uno de otro archivo para diferentes rutas ...

esperanza esto ayuda.

+0

Ahora mismo es solo un servidor de archivos y un servidor socket.io, sin embargo, al final también tendré lógica de juego para determinar las posiciones de jugador dadas las actualizaciones de movimiento y tendré que tener lógica de minimización de retraso que mire el ping de cada cliente y las estimaciones estado del juego en el que se encuentran actualmente a juzgar a partir de los datos existentes. Tener algo de lógica para adelantar el tiempo, algo de lógica para rebobinar el tiempo, algo de lógica para mover jugadores, algo de lógica para manejar datos de red, y algo de lógica para manejar archivos significaba que quería separar TODO en diferentes archivos, idealmente. No solo las cosas de socket.io – stevendesu

+0

es solo el comienzo - con los archivos que ha publicado. puede hacer más de un 'var xxx = require ('./ xxx');' y dividir su aplicación en varios archivos. Estuve ayer en el mongodb conf y alguien de 10gen mostró un juego basado en node/mongo/websockets (https://github.com/christkv/mongoman) que está enviando datos BSON por el socket y decodifica los datos en el cliente - hace para una comunicación más rápida entre cliente/servidor ... ¡¿tal vez es interesante para ti ?! – pkyeck

0

tengo otra solución. Puede usar require.js creando un módulo y pasar "aplicación" como argumento. Dentro del módulo puede iniciar socket.io y organizar sus sockets.

app.js:

var requirejs = require('requirejs'); 

    requirejs.config({ 
     baseUrl: './', 
     nodeRequire: require 
    }); 

    requirejs(['sockets'], function(sockets) { 

    var app = require('http').createServer() 
     , fs = require('fs') 
     , io = sockets(app); 

     // do something 
     // add more sockets here using "io" resource 

    }); 

En sus socket.js módulo que puede hacer algo como esto:

define(['socket.io'], function(socket){ 
    return function(app){ 
     var server = app.listen(3000) 
     , io  = socket.listen(server); 

     io.sockets.on('connection', function (socket) { 
     console.log('connected to socket'); 

     socket.emit('news', { hello: 'world' }); 
     socket.on('my other event', function (data) { 
      console.log(data); 
     }); 

     // more more more 

     }); 

     return io; 
    } 
    }); 

espero que ayuda con mi contribución.

+1

En caso de que alguien lea esto se pregunte, no, no hay ninguna razón en absoluto para usar AMD dentro del nodo –

+0

Es solo una alternativa, no es la única manera de hacerlo –

Cuestiones relacionadas