2012-03-14 10 views
60

Jestem dość nowym użytkownikiem node.js i odkryłem, że jego dość skomplikowane oddzielenie projektu na wiele plików w miarę wzrostu rozmiaru projektu. Miałem jeden duży plik, który wcześniej służył zarówno jako serwer plików, jak i serwer Socket.IO dla gry HTML5 dla wielu graczy. Idealnie chcę oddzielić serwer plików, logikę socket.IO (odczytywanie informacji z sieci i zapisywanie ich w buforze z sygnaturą czasową, a następnie wysyłanie ich do wszystkich innych graczy) oraz logikę gry.Separacja serwera plików i logiki socket.io w węźle node.js

Za pomocą pierwszego przykładu z pliku socket.io, aby zademonstrować mój problem, zwykle są dwa pliki. app.js to serwer, a index.html jest wysyłany do klienta.

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> 

Do oddzielnego serwera plików i logiki serwera gry musiałbym funkcję "obsługi" zdefiniowane w jednym pliku, musiałbym anonimowa funkcja użyła wywołania zwrotnego dla pliku io.sockets.on() w innym pliku i potrzebowałbym jeszcze trzeciego pliku, aby z powodzeniem objąć oba te pliki. Na razie próbowałem następujące:

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

} 

Wydaje się to do pracy (statyczny zawartość jest poprawnie obsługiwana, a konsola wyraźnie pokazuje handshake z Socket.IO, gdy klient łączy się), chociaż nie ma danych kiedykolwiek wysłany. To tak, jakby socket.emit() i socket.on() nigdy nie były wywoływane. Nawet zmodyfikowałem handler() w gameserver.js, aby dodać console.log('User connected');, ale to nigdy nie jest wyświetlane.

Jak mogę mieć Socket.IO w jednym pliku, serwer plików w innym, i nadal oczekuję, że obie będą działać poprawnie?

+4

Czy znasz ramy ekspresowe js? http://expressjs.com/ jest świetny i naprawdę pomaga w tworzeniu struktury aplikacji. jest mnóstwo przykładów na github (https://github.com/visionmedia/express/tree/master/examples) może jest coś, co może ci pomóc w rozwiązaniu problemu ... – pkyeck

+1

@pkyeck: czytam dalej expressjs teraz, aby spróbować i dowiedzieć się, jak może mi to pomóc, ale jak dotąd wydaje się bardziej skomplikowany niż to, czego potrzebuję. Wszystko, czego naprawdę chcę, to oddzielić logikę serwera gier i serwera plików na dwa osobne pliki, a następnie trzeci plik, który poprawnie uruchamia oba serwery. – stevendesu

+0

Czy masz czas, aby sprawdzić moją "nową" odpowiedź? – pkyeck

Odpowiedz

74

W socket.io 0.8, należy dołączyć zdarzenia używając io.sockets.on('...'), chyba że używasz nazw, to wydaje się być brakuje sockets część:

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

To chyba lepiej unikać łączenia w ten sposób (możesz użyć obiektu io później). Droga robię to teraz:

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

Następnie po utworzeniu serwera app:

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

Świetna odpowiedź, próbując przesłać to do krakenJS, ale moduł socket.io nigdy się nie uruchamia:/ – Ms01

+1

Nie używamy "return io", prawda? to tylko dla var io. – Sobiaholic

+0

Czy chcę wywołać żądanie emisji? np. 'app.get ('/ some/url', function (req, res) {// Chcę się tutaj wyemitować})' –

5

Zrobiłbym coś takiego.

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

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


         }); 
       }); 
     } 
}; 

ja po prostu skopiować & wklejone niektóre z mojego starego kodu - tak naprawdę nie wiem, co się zmieniło w ciągu ostatnich wersjach gniazda. io, ale to bardziej dotyczy struktury niż rzeczywistego kodu.

i chciałbym używać tylko 2 pliki do swoich celów, a nie 3. gdy myślisz o podzielenie go dalej, może jeszcze jeden plik dla różnych dróg ...

nadzieję, że to pomaga.

+0

W tej chwili jest to tylko serwer plików i serwer socket.io, ale w końcu będę miał również logikę gry, aby określić pozycje graczy podane aktualizacje ruchu i będę musiał mieć logikę minimalizacji opóźnień, która sprawdza ping każdego klienta i szacuje, które stan gry, który obecnie oceniają na podstawie istniejących danych. Mając trochę logiki do szybkiego przewijania, trochę logiki do przewinięcia czasu, trochę logiki do przenoszenia graczy, trochę logiki do obsługi danych sieciowych i trochę logiki do obsługi plików oznaczało, że chciałem idealnie oddzielić WSZYSTKO na różne pliki. Nie tylko rzeczy na socket.io. – stevendesu

+0

to tylko początek - z opublikowanymi plikami. możesz zrobić więcej niż jeden 'var xxx = require ('./ xxx');' i podzielić aplikację na wiele plików. byłem wczoraj w mongodb conf i ktoś z 10gen pokazał grę opartą na node/mongo/websockets (https://github.com/christkv/mongoman) wysyła dane BSON przez gniazdo i dekoduje dane na kliencie - czyni dla szybszej komunikacji między klientem/serwerem ... może to dla ciebie interesujące !? – pkyeck

0

mam innego rozwiązania. Możesz użyć require.js tworząc moduł i przekazać "aplikację" jako argument. W tym module możesz uruchomić socket.io i uporządkować swoje gniazda.

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 

    }); 

W swoim socket.js moduł można zrobić coś takiego:

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

mam nadzieję pomóc z moim wkładem.

+1

Jeśli ktoś czyta to, zastanawia się, nie, w ogóle nie ma powodu używać AMD w węźle. –

+0

To tylko alternatywa, to nie jedyny sposób –