2013-01-22 92 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