在node.js中分离文件服务器和socket.io逻辑


75

我对node.js相当陌生,并且发现随着项目规模的扩大,将项目分为多个文件非常复杂。我之前有一个大文件,它同时用作文件服务器和用于多人HTML5游戏的Socket.IO服务器。理想情况下,我希望将文件服务器,socket.IO逻辑(从网络读取信息并将其写入带有时间戳的缓冲区,然后将其发送给所有其他播放器)和游戏逻辑分开。

使用socket.io中的第一个示例来演示我的问题,通常有两个文件。app.js是服务器,index.html并发送给客户端。

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>

要分离文件服务器和游戏服务器逻辑,我需要在一个文件中定义的函数“ handler”,我需要将用于io.sockets.on()的回调的匿名函数存在于另一个文件中,并且我还需要一个第三个文件以成功包含这两个文件。现在,我尝试了以下方法:

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

游戏服务器:

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

}

尽管似乎从未发送过数据,但这似乎可行(静态内容已正确提供,并且当客户端连接时控制台清楚地显示了与Socket.IO的握手)。好像从来没有真正调用过socket.emit()和socket.on()。我什至修改了handler()gameserver.js以添加,console.log('User connected');但从未显示。

如何在一个文件中拥有Socket.IO,在另一个文件中拥有文件服务器,又如何期望两者都能正常运行?


4
您知道Express js框架吗?expressjs.com很棒,确实可以帮助您构建应用程序。github上有很多例子(github.com/visionmedia/express/tree/master/examples)也许有些东西可以帮助您解决问题……
pkyeck 2012年

1
@pkyeck:我现在正在阅读expressjs,试图弄清楚它如何使我受益,但是到目前为止,这似乎比我需要的要复杂。我真正想要的只是将游戏服务器和文件服务器的逻辑分成两个单独的文件,然后有第三个文件来正确启动两个服务器。
stevendesu 2012年

您有时间检查我的“新”答案吗?
pkyeck 2012年

@pkyeck我已经看过它了,尽管看起来它只是掩盖问题而不是解决问题。不是sockets.js是一个大文件,而不是app.js。我希望没有单个海量文件,但是每个功能都有单独的文件。越来越多的node.js似乎更多的是麻烦而不是祝福。
stevendesu 2012年

Answers:


91

在socket.io 0.8中,应该使用来附加事件io.sockets.on('...'),除非使用名称空间,否则似乎缺少以下sockets部分:

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

最好避免以这种方式链接它(您以后可能要使用该io对象)。我现在这样做的方式是:

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

然后在创建服务器后app

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

2
很好的答案,尝试将其移植到krakenJS,但socket.io模块从未启动:/
Ms01 2014年

1
我们不使用'return io'对吗?它仅用于var io。
Sobiaholic

3
如果我要触发发射请求?对于前夫。app.get('/some/url',function(req,res){ // I want to emit here })
迪派中号

6

我会做这样的事情。

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

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


                        });
                });
        }
};

我只是复制并粘贴了我的一些旧代码-真的不知道socket.io的最新版本中发生了什么变化,但这更多的是结构而不是实际代码。

而且我只会将2个文件用于您的目的,而不是3个。当您考虑将其进一步拆分时,也许还有一个用于不同路由的文件...

希望这可以帮助。


现在它只是一个文件服务器和一个socket.io服务器,但是最终我还将具有游戏逻辑来确定玩家位置(根据移动更新),并且我将需要滞后最小化逻辑来查看每个客户端的ping并估算哪个游戏说明他们当前正在根据现有数据进行判断。拥有一些可以快进的逻辑,一些可以倒带时间的逻辑,一些可以移动播放器的逻辑,一些可以处理网络数据的逻辑以及一些可以处理文件的逻辑,这意味着我希望将一切都理想地分离为不同的文件。不只是socket.io的东西。
stevendesu 2012年

这只是开始-与您发布的文件有关。您可以执行多个操作,var xxx = require('./xxx');然后将您的应用拆分为多个文件。昨天我在mongodb conf上,来自10gen的某人展示了一个基于node / mongo / websockets(github.com/christkv/mongoman)的游戏,他正在通过套接字发送BSON数据并解码客户端上的数据-使通讯速度更快客户端/服务器之间...也许对您来说很有趣!
pkyeck 2012年


0

我有另一个解决方案。您可以使用require.js创建模块并将“ app”作为参数传递。在模块内,您可以启动socket.io并组织您的套接字。

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

  });

在您的socket.js模块中,您可以执行以下操作:

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

希望对您有所帮助。


2
万一有读者读到这是在想,不,根本没有理由在节点内使用AMD。
里卡多·托马西

1
这只是一种选择,不是唯一的方法
MarcoGodínez2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.