2012-03-14 3 views
60

Tôi khá mới đối với node.js và tôi đã tìm thấy việc tách một dự án thành nhiều tệp phức tạp khi dự án phát triển về kích thước. Tôi đã có một tệp lớn trước đó phục vụ như một máy chủ tệp và máy chủ Socket.IO cho trò chơi HTML5 nhiều người chơi. Tôi lý tưởng muốn tách máy chủ tập tin, logic socket.IO (đọc thông tin từ mạng và ghi nó vào một bộ đệm với một dấu thời gian, sau đó phát ra nó cho tất cả người chơi khác), và logic trò chơi.Tách logic máy chủ tệp và socket.io trong node.js

Sử dụng ví dụ đầu tiên từ socket.io để minh họa sự cố của tôi, có hai tệp bình thường. app.js là máy chủ và index.html được gửi cho khách hàng.

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> 

Để máy chủ tập tin riêng biệt và logic trò chơi máy chủ tôi sẽ cần các chức năng "xử lý" được định nghĩa trong một tập tin, tôi sẽ cần chức năng ẩn danh đã sử dụng gọi lại cho io.sockets.on() để ở trong một tệp khác và tôi sẽ cần một tệp thứ ba để bao gồm thành công cả hai tệp này. Để bây giờ tôi đã thử như sau:

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

} 

Điều này dường như làm việc (các tĩnh nội dung được phục vụ đúng cách và giao diện điều khiển hiển thị rõ ràng một cái bắt tay với Socket.IO khi khách hàng kết nối) mặc dù không có dữ liệu đã từng gửi. Nó giống như socket.emit() và socket.on() chưa bao giờ được gọi. Tôi thậm chí đã sửa đổi handler() trong số gameserver.js để thêm console.log('User connected'); tuy nhiên điều này không bao giờ được hiển thị.

Làm cách nào để có Socket.IO trong một tệp, máy chủ tệp ở một tệp khác và vẫn mong cả hai hoạt động chính xác?

+4

bạn có biết khung công tác js nhanh không? http://expressjs.com/ thật tuyệt vời và thực sự giúp bạn cấu trúc ứng dụng của mình. có rất nhiều ví dụ về github (https://github.com/visionmedia/express/tree/master/examples) có thể có điều gì đó có thể giúp bạn giải quyết vấn đề của mình ... – pkyeck

+1

@pkyeck: Tôi đang đọc bây giờ tôi đã cố gắng và tìm ra cách nó có thể mang lại lợi ích cho tôi, nhưng cho đến nay nó có vẻ phức tạp hơn những gì tôi cần. Tất cả những gì tôi thực sự muốn là phân tách logic của mình cho máy chủ trò chơi và máy chủ tệp thành hai tệp riêng biệt sau đó có tệp thứ ba khởi động đúng cả hai máy chủ. – stevendesu

+0

bạn có thời gian để kiểm tra câu trả lời "mới" của tôi không? – pkyeck

Trả lời

74

Trong socket.io 0.8, bạn nên đính kèm các sự kiện sử dụng io.sockets.on('...'), trừ khi bạn đang sử dụng không gian tên, bạn dường như thiếu sockets phần:

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

Đây có thể là tốt hơn để tránh chaining nó theo cách đó (bạn có thể muốn sử dụng đối tượng io một lát sau). Con đường tôi đang làm này ngay bây giờ:

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

Sau đó, sau khi tạo server app:

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

Câu trả lời tuyệt vời, cố gắng chuyển cổng này sang krakenJS nhưng mô-đun socket.io không bao giờ bắt đầu:/ – Ms01

+1

Chúng tôi không sử dụng 'return io' ngay? nó chỉ dành cho var io. – Sobiaholic

+0

Nếu tôi muốn kích hoạt yêu cầu phát ra? cho ví dụ, 'app.get ('/ some/url', hàm (req, res) {// Tôi muốn phát ra ở đây})' –

5

tôi sẽ làm một việc như thế này.

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

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


         }); 
       }); 
     } 
}; 

tôi chỉ cần sao chép & dán một số mã cũ của tôi - không thực sự biết những gì thay đổi trong phiên bản cuối cùng của socket. io, nhưng đây là cấu trúc nhiều hơn mã thực tế.

và tôi sẽ chỉ sử dụng 2 file cho mục đích của bạn, chứ không phải 3. khi bạn nghĩ về việc tách nó lên hơn nữa, có thể một tập tin khác cho tuyến đường khác nhau ...

hy vọng điều này giúp.

+0

Ngay bây giờ nó chỉ là một máy chủ tập tin và một máy chủ socket.io, tuy nhiên cuối cùng tôi cũng sẽ có logic trò chơi để xác định vị trí của người chơi cho các cập nhật chuyển động và tôi sẽ cần phải có logic giảm thiểu trễ xem xét ping của từng khách hàng và ước tính trạng thái trò chơi mà họ hiện đang đánh giá từ dữ liệu hiện có. Có một số logic để tua lại thời gian, một số logic để chuyển đổi thời gian, một số logic để di chuyển người chơi, một số logic để xử lý dữ liệu mạng và một số logic để xử lý các tệp có nghĩa là tôi muốn tách mọi thứ thành các tệp khác nhau. Không chỉ là công cụ socket.io. – stevendesu

+0

chỉ là khởi đầu - với các tệp bạn đã đăng. bạn có thể làm nhiều hơn một 'var xxx = require ('./ xxx');' và chia ứng dụng của bạn thành nhiều tệp. Tôi đã ở mongodb conf ngày hôm qua và một người nào đó từ 10gen cho thấy một trò chơi dựa trên nút/mongo/websockets (https://github.com/christkv/mongoman) anh ấy đang gửi dữ liệu BSON trên socket và giải mã dữ liệu trên máy khách - làm cho để giao tiếp nhanh hơn giữa máy khách/máy chủ ... có thể nó thú vị cho bạn !? – pkyeck

0

Tôi đã một giải pháp khác. Bạn có thể sử dụng require.js để tạo mô-đun và chuyển "ứng dụng" làm đối số. Trong mô-đun, bạn có thể bắt đầu socket.io và tổ chức các ổ cắm của bạn.

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 

    }); 

Trong socket.js bạn mô-đun bạn có thể làm một cái gì đó như thế này:

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

Tôi hy vọng giúp bạn với đóng góp của tôi.

+1

Trong trường hợp ai đó đọc nó tự hỏi, không, không có lý do gì cả để sử dụng AMD trong nút. –

+0

Nó chỉ là một thay thế, không phải là cách duy nhất để làm –