2013-01-22 35 views
0

我目前正在嘗試開發一個與node.js服務器交談的簡單Flash遊戲。使用ExpressJS的遊戲+ Web服務器

我的問題是這樣的: 我該如何做一個服務器來區分Web請求和遊戲請求?

下面是我所做的一切細節:

以前,我用了netstatic模塊來處理分別從遊戲客戶端和瀏覽器的請求。

TwoServers.js

// Web server 
var file = new staticModule.Server('./public'); 
http.createServer(function(req, res){ 
    req.addListener('end', function(){ 
     file.serve(req, res, function(err, result){ 
        // do something 
     }); 
    }); 
}).listen(port1, "127.0.0.1"); 

// Game Server 
var server = net.createServer(function(socket) 
{ 
    // handle messages to/from Flash client 
    socket.setEncoding('utf8'); 
    socket.write('foo'); 
    socket.on('data', onMessageReceived); 
}); 
server.listen(port2, "127.0.0.1"); 

我想做到以上只是一個Express服務器在一個端口上監聽,但我不知道如何去這樣做。

這裏就是我想它可能看起來像(實際上不工作):

OneServer.js

var app = express(); 
app.configure(function() 
{ 
    // ... 
    app.use('/',express.static(path.join(__dirname, 'public'))); // The static server 
}); 

app.get('/', function(req, res) // This is incorrect (expects http requests) 
{ 
    // Handle messages to/from Flash client 
    var socket = req.connection; 
    socket.setEncoding('utf8'); 
    socket.write('foo'); 
    socket.on('data', onMessageReceived); 
}); 
app.listen(app.get('port')); // Listen in on a single port 

但我希望能夠從網頁請求分化和遊戲的要求。

:可使用ActionScript的XMLSocket使TCP請求,因此使用app.get( '/')是不正確的原因有兩個:

  1. 當Flash寫入到插座,不使用http協議,所以當遊戲嘗試連接時app.get('/')不會被觸發。

  2. 因爲我無權修改net.Socket對象,所以我不能指望從/正確讀取或寫入正確的套接字。相反,我將讀/寫與網頁請求關聯的套接字。

對此的任何幫助將非常感激(特別是如果我推斷這是錯誤的方式)。

回答

2

當一個TCP連接打開到給定的端口時,服務器(Node + Express)無法告訴誰建立了連接(無論是瀏覽器還是自定義客戶端)。

因此,您的自定義客戶端必須說話HTTP,如果它希望與Express服務器坐在端口80,否則溝通,你寄過來剛剛打開的插座(在你的自定義協議)的數據將只是看起來像垃圾到Express,它會關閉連接。

但是,這並不意味着您不能通過使用TCP流來說出自定義協議,您只需要說出HTTP 第一個並要求切換協議。 HTTP提供了一個機制來完成這項工作(Upgrade標題),實際上它是如何實現WebSocket的。

當您的Flash客戶端首先打開一個TCP連接到你的服務器,它應該發送(注:換行必須被作爲CRLF字符,又名\r\n

GET /gamesocket HTTP/1.1 
Upgrade: x-my-custom-protocol/1.0 
Host: example.com 
Cache-Control: no-cache 
​ 

Upgrade的價值是你的選擇, Host必須發送所有HTTP請求,並且Cache-Control標頭確保沒有中間代理服務於此請求。注意空行,它表示請求已完成。

服務器響應:

HTTP/1.1 101 Switching Protocols 
Upgrade: x-my-custom-protocol/1.0 
Connection: Upgrade 
​ 

同樣,一個空行表示標頭是完整的,而且最終CRLF後,你現在可以免費送你通過TCP連接的任何格式喜歡的任何數據。

爲了實現這種服務器端:

app.get('/gamesocket', function(req, res) { 
    if (req.get('Upgrade') == 'x-my-custom-protocol/1.0') { 
     res.writeHead(101, { Upgrade: req.get('Upgrade'), Connection: 'Upgrade' }); 

     // `req.connection` is the raw net.Socket object 
     req.connection.removeAllListeners(); // make sure Express doesn't listen to the data anymore... we've got it from here! 

     // now you can do whatever with the socket 
     req.connection.setEncoding('utf8');    
     req.connection.write('foo'); 
     req.connection.on('data', onMessageReceived); 
    } else res.send(400); // bad request 
}); 

當然,要記住TCP是基於消息的協議,它只是提供了一個,因此a的data事件Socket可以將單個邏輯消息分成多個事件,甚至可以在單個事件中包含多個邏輯消息。準備手動緩衝數據。

您的其他選項是使用socket.io,它在WebSockets協議之上實現WebSockets服務器和自己的協議。 WebSockets協議是基於消息的。它主要就像我在這裏概述的那樣工作,然後在HTTP協商之後在TCP連接之上添加消息成幀層,以便應用程序不必擔心數據流。 (如果需要,使用WebSockets也會打開從HTML頁面連接到服務器的可能性。)

有一個Flash socket.io client可用。

+0

感謝您的回答,這是有道理的。我可能不得不使用AS3 [套接字](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/Socket.html)類來定製標頭,如果我要走這條路。雖然使用express/http模塊的多個端口以及網絡模塊會被認爲是不好的做法? – funseiki

+0

這取決於您是否確定某些用戶無法使用您的遊戲。許多網絡環境(公司網絡,公共WiFi,終端用戶的偏執防火牆等)阻止外出連接到除端口80之外的任何內容,因此用戶將能夠加載您的網站和swf,但是然後遊戲將無法通過* n *端口連接到您的服務器。通過進行HTTP升級,您知道如果用戶可以訪問您的網站,遊戲也可以連接。 – josh3736

+0

因爲我在Heroku上託管,所以似乎我無法在多個端口上託管。所以我認爲你是對的,而且這種方法可能是最好的選擇。 – funseiki