Trennen der Dateiserver- und Socket.io-Logik in node.js

75

Ich bin ziemlich neu in node.js und habe festgestellt, dass es ziemlich kompliziert ist, ein Projekt in mehrere Dateien zu unterteilen, wenn das Projekt größer wird. Ich hatte eine große Datei, die sowohl als Dateiserver als auch als Socket.IO-Server für ein Multiplayer-HTML5-Spiel diente. Ich möchte im Idealfall den Dateiserver, die Socket.IO-Logik (Lesen von Informationen aus dem Netzwerk und Schreiben in einen Puffer mit einem Zeitstempel, dann an alle anderen Spieler senden) und die Spielelogik trennen.

Anhand des ersten Beispiels aus socket.io, um mein Problem zu demonstrieren, gibt es normalerweise zwei Dateien. app.jsist der Server und index.htmlwird an den Client gesendet.

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>

Um die Logik von Dateiserver und Spielserver zu trennen, müsste die in einer Datei definierte Funktion "Handler" verwendet werden. Die anonyme Funktion würde einen Rückruf für io.sockets.on () verwenden, um in einer anderen Datei zu sein, und ich würde noch eine benötigen dritte Datei, um diese beiden Dateien erfolgreich einzuschließen. Im Moment habe ich Folgendes versucht:

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;
    }
}

Spieleserver:

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);
    }

}

Dies scheint zu funktionieren (der statische Inhalt wird ordnungsgemäß bereitgestellt und die Konsole zeigt deutlich einen Handshake mit Socket.IO an, wenn der Client eine Verbindung herstellt), obwohl niemals Daten gesendet werden. Es ist, als würden socket.emit () und socket.on () niemals aufgerufen. Ich habe sogar handler () geändert, gameserver.jsum hinzuzufügen, console.log('User connected');aber dies wird nie angezeigt.

Wie kann ich Socket.IO in einer Datei und einen Dateiserver in einer anderen Datei haben und trotzdem erwarten, dass beide ordnungsgemäß funktionieren?

stevendesu
quelle
4
Kennen Sie das Express JS Framework? expressjs.com ist großartig und hilft Ihnen wirklich bei der Strukturierung Ihrer Anwendung. Es gibt eine Menge Beispiele auf Github ( github.com/visionmedia/express/tree/master/examples ). Vielleicht gibt es etwas, das Ihnen bei Ihrem Problem helfen kann ...
Pkyeck
1
@pkyeck: Ich lese gerade Expressjs, um herauszufinden, wie es mir nützen kann, aber bisher scheint es komplizierter zu sein als das, was ich brauche. Alles, was ich wirklich möchte, ist, meine Logik für den Spieleserver und den Dateiserver in zwei separate Dateien zu trennen und dann eine dritte Datei zu haben, die beide Server ordnungsgemäß startet.
Stevendesu
Hattest du die Zeit, meine "neue" Antwort zu überprüfen?
Pkyeck
@pkyeck Ich habe es mir angesehen, obwohl es so aussieht, als würde es das Problem nur maskieren und nicht lösen. Nicht sockets.js ist die EINE MASSIVE DATEI anstelle von app.js. Ich möchte keine einzelnen massiven Dateien haben, sondern separate Dateien für jede Funktion. Immer mehr node.js scheint eher ein Ärger als ein Segen zu sein.
Stevendesu

Antworten:

91

In socket.io 0.8 sollten Sie Ereignisse anhängen mit io.sockets.on('...'): Wenn Sie keine Namespaces verwenden, scheint Ihnen der socketsTeil zu fehlen :

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

Es ist wahrscheinlich besser, eine Verkettung auf diese Weise zu vermeiden (möglicherweise möchten Sie das ioObjekt später verwenden). So mache ich das gerade:

// 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
}

Dann nach dem Erstellen des Servers app:

// main.js
var io = require('./lib/sockets').listen(app)
Ricardo Tomasi
quelle
2
Tolle Antwort, versuchen, dies auf krakenJS zu portieren, aber das socket.io-Modul startet nie: /
Ms01
1
Wir verwenden nicht 'return io', oder? es ist nur für die var io.
Sobiaholic
3
Wenn ich eine Emit-Anfrage auslösen möchte? zum Beispielapp.get('/some/url',function(req,res){ // I want to emit here })
Deepak M
6

Ich würde so etwas tun.

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);

und 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]);
                                }


                        });
                });
        }
};

Ich habe nur einen Teil meines alten Codes kopiert und eingefügt - ich weiß nicht wirklich, was sich in den letzten Versionen von socket.io geändert hat, aber hier geht es mehr um die Struktur als um den tatsächlichen Code.

und ich würde nur 2 Dateien für Ihre Zwecke verwenden, nicht 3. Wenn Sie darüber nachdenken, es weiter aufzuteilen, vielleicht eine andere Datei für verschiedene Routen ...

hoffe das hilft.

pkyeck
quelle
Im Moment ist es nur ein Dateiserver und ein socket.io-Server, aber irgendwann werde ich auch eine Spielelogik haben, um die Spielerpositionen bei Bewegungsaktualisierungen zu bestimmen, und ich werde eine Logik zur Minimierung der Verzögerung haben, die den Ping jedes Clients betrachtet und welches Spiel schätzt Geben Sie an, dass sie derzeit anhand der vorhandenen Daten urteilen. Eine Logik zum schnellen Vorlauf, eine Logik zum Zurückspulen, eine Logik zum Verschieben von Spielern, eine Logik zum Verarbeiten von Netzwerkdaten und eine Logik zum Verarbeiten von Dateien bedeutete, dass ich ALLES idealerweise in verschiedene Dateien aufteilen wollte. Nicht nur das socket.io Zeug.
Stevendesu
Es ist nur der Anfang - mit den Dateien, die Sie gepostet haben. Sie können mehrere ausführen var xxx = require('./xxx');und Ihre App in mehrere Dateien aufteilen. Ich war gestern bei der Mongodb Conf und jemand von 10gen zeigte ein Spiel basierend auf Node / Mongo / Websockets ( github.com/christkv/mongoman ). Er sendet BSON-Daten über den Socket und decodiert die Daten auf dem Client - sorgt für eine schnellere Kommunikation zwischen Client / Server ... vielleicht ist es interessant für Sie!?
Pkyeck
0

Ich habe eine andere Lösung. Sie können require.js verwenden, um ein Modul zu erstellen und "app" als Argument zu übergeben. Innerhalb des Moduls können Sie socket.io starten und Ihre Sockets organisieren.

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

  });

In Ihrem socket.js- Modul können Sie Folgendes tun:

  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;
    }
  });

Ich hoffe, ich helfe Ihnen mit meinem Beitrag.

Marco Godínez
quelle
2
Falls sich jemand fragt, der dies liest, nein, es gibt überhaupt keinen Grund, AMD innerhalb des Knotens zu verwenden.
Ricardo Tomasi
1
Es ist nur eine Alternative, nicht die einzige Möglichkeit
Marco Godínez