sockets - 使用 Node.js 进行游戏配对时如何设计

标签 sockets node.js

我使用node.js进行游戏配对(例如,多个客户端连接服务器。如果有多个玩家,则它们会相互连接;否则将被踢30秒)。

目前,我正在使用套接字进行连接(这可以检测意外丢失的连接)。但我无法找到一种优雅的配对方式:

var net = require('net');
var _clients = new Array();

net.createServer(function(_socket) {
  _socket.on('data', function(_data) {
    //Parse client data
    _clients.push(_socket);
    setTimeout(function(){
      _socket.write('kicked\n');
    },30*1000);
  _socket.on('close', function(data) {
    //Delete _socket from _clients
  }
}).listen(6969, '127.0.0.1');

setInterval(function(){
  var pair = new Array();
  while(_clients.length>2)
  {
    var _s1 = _clients.pop(), _s2 = _clients.pop();
    // Pair _s1 & _s2
  }
},2*1000);

当前代码可以工作,但设计确实很糟糕:(

(1)使用SetInterval,而不是异步调用。 (2)维护像_clients这样的数组很不方便,因为我必须处理“被踢”/丢失连接/配对或其他情况。

PS。目前我正在按时间顺序配对客户,但可能需要随机配对或其他条件,以避免在线玩家不多时总是配对相同的人。

最佳答案

为什么不使用类似下面的东西?

没有连接池

var net = require('net')
, pendingPair = null;

net.createServer(function(_socket) {
  _socket.on('data', function(_data) {
    //Parse client data
    if(!pendingPair) {
      pendingPair = _socket;
    } else {
      //  Now you have a pair!
      var p1 = pendingPair
        , p2 = _socket;

      pendingPair = null;
    }
}).listen(6969, '127.0.0.1');

一旦建立连接,您就会获得自动配对。您仍然需要在某处跟踪这些套接字以踢出客户端并断开连接,但您应该能够摆脱 setIntervals。

使用连接池

var net = require('net')
  , _ = require('underscore')._
  , clients = {}
  , games = {};

function setKickTimer(socket) {
    socket.kickTimer = setTimeout(function() {
        socket.write('kicked\n');
    }, 30 * 1000);
}

net.createServer(function(socket) {
    socket.id = Math.floor(Math.random() * 1000);
    setKickTimer(socket);
    clients[socket.id] = socket;

    socket.on('data', function(data) {
        socket.data = parseData(data);
    }

    socket.on('close', function(data) {
        var opponent = _.find(clients, function(client) { return client.opponentId === socket.id; });
        //  The opponent is no longer part of a pair.
        if(opponent) {
            delete opponent.opponentId;
            setKickTimer(opponent);
        }

        delete clients[socket.id];
    }

}).listen(6969, '127.0.0.1');

setInterval(function(){
    //  Get the client ids of clients who are not matched, and randomize the order
    var unmatchedClientIds = _.shuffle(_.keys(_.filter(clients, function(client) { return !client.opponentId; })));
    while(unmatchedClientIds > 2) {
        var c1 = unmatchedClientIds.pop(),
          , c2 = unmatchedClientIds.pop();

        clearTimeout(clients[c1].kickTimer);
        clearTimeout(clients[c2].kickTimer);
        clients[c1].opponentId = c2;
        clients[c2].opponentId = c1;
    }
},2*1000);

这不是一个完整的工作解决方案,但它应该让您了解如何管理断开的连接并将用户从队列中踢出。请注意,我正在使用 underscore.js让对集合的操作变得更加简单。

关于sockets - 使用 Node.js 进行游戏配对时如何设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11281762/

相关文章:

javascript - 在 promise 中链接三个查询

java - 从两个单独的类读取 Java 套接字,最新的线程干扰旧线程

c++ - 无法接收 UDP 广播消息

sockets - 套接字和文件描述符

c#:是否有任何理由支持异步套接字调用在我自己的线程池中进行同步调用?

javascript - 如何检查函数是否在 Node 的工作线程中运行?

json - 以 JSON 格式打印用户详细信息,如 php 中的 foreach

node.js - 带有自定义 "company_id" header 的 GET 请求在本地有效,但 header 不存在于 GCP App Engine 中

node.js - 在 Flow 中扩展快速请求类

c++ - recv()/send()(在 Socket 中)或 read()/write()(在 CFile 中)错误