【问题标题】:Game + Web Server using ExpressJS使用 ExpressJS 的游戏 + Web 服务器
【发布时间】:2013-01-23 23:04:32
【问题描述】:

我目前正在尝试开发一个与 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 对象,我不能期望从/向正确的套接字读取或写入。相反,我将读取/写入与网页请求关联的套接字。

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

【问题讨论】:

    标签: actionscript-3 node.js sockets express


    【解决方案1】:

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

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

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

    有一个Flash socket.io client 可用。

    【讨论】:

    • 感谢您的回答,这是有道理的。如果我要走那条路,我可能不得不使用 AS3 Socket 类来自定义标头。但是,将多个端口与 express/http 模块和 net 模块一起使用会被认为是不好的做法吗?
    • 这取决于您是否可以接受某些用户无法使用您的游戏。许多网络环境(企业网络、公共 WiFi、最终用户的偏执防火墙等)会阻止与端口 80 以外的任何地方的传出连接,因此用户将能够加载您的网站和 swf,但随后游戏将无法加载在端口 n 上连接回您的服务器。通过进行 HTTP 升级,您知道如果用户可以访问您的网站,那么游戏也将能够连接。
    • 因为我在 Heroku 上托管,所以我似乎无法在多个端口上托管。所以我认为你是对的,这种方法可能是要走的路。
    • 将此标记为解决方案。将使用 socket.io 路由,尽管这个库看起来有点过时(socket.io 是 0.9.x,FlashSocket.IO 似乎支持
    猜你喜欢
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多