0

我目前正在尝试开发一个与 node.js 服务器对话的简单 Flash 游戏。

我的问题是:我该如何制作一个服务器来区分网络请求和游戏请求?

以下是我所做的详细信息:

以前,我使用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对象,因此我不能期望从/向正确的套接字读取或写入。相反,我将读取/写入与网页请求关联的套接字。

对此的任何帮助将不胜感激(特别是如果我以错误的方式推理)。

4

1 回答 1

2

当 TCP 连接打开到给定端口时,服务器(Node + Express)无法告诉谁建立了该连接(无论是浏览器还是您的自定义客户端)。

因此,如果您的自定义客户端希望与位于端口 80 上的 Express 服务器通信,则它必须使用 HTTP。否则,您通过新打开的套接字(在您的自定义协议中)发送的数据对 Express 来说就像垃圾一样,而且它会关闭连接。

但是,这并不意味着您不能让 TCP 流使用自定义协议——您只需先使用 HTTP要求切换协议。HTTP 提供了一种机制来实现这一点(Upgrade标头),实际上这就是 WebSockets 的实现方式。

当您的 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
​

同样,空行表示标头已完成,并且在 final 之后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不是基于消息的协议,它只提供一个,因此dataa 的事件Socket可以将单个逻辑消息分割成多个事件,甚至可以在单个事件中包含多个逻辑消息。准备手动缓冲数据。

您在这里的另一个选择是使用socket.io,它在 WebSockets 协议之上实现了一个 WebSockets 服务器以及它自己的协议。WebSockets 协议基于消息的。它主要像我在这里概述的那样工作,然后在 HTTP 协商之后在 TCP 连接之上添加一个消息框架层,这样应用程序就不必担心数据流。(如果需要,使用 WebSockets 还可以从 HTML 页面连接到您的服务器。)

有一个Flash socket.io 客户端可用。

于 2013-01-23T05:21:14.723 回答