Как я могу найти время отклика (задержку) клиента в Nodejs с сокетами (Socket.io)?

StackOverflow https://stackoverflow.com/questions/4071258

Вопрос

Я пытаюсь создать многопользовательскую игру с Nodejs, и я хочу синхронизировать действие между клиентами.

Что было бы лучшим способом найти задержку (время, когда запрос предпринял, чтобы вернуться к клиенту) между клиентом и сервером?

Моя первая идея заключалась в том, что клиент № 1 может отправить временную метку с помощью запроса, поэтому, когда клиент № 2 получит действие клиента № 1, он будет настроить скорость действия, чтобы удалить задержку запроса. Но проблема в том, что, возможно, в системе дата времени двух клиентов не идентичны, поэтому невозможно, два знания задержки катушки по запросу клиента № 1.

Другое решение было использовать временную метку сервера, но теперь, как я могу узнать задержку клиента?

Это было полезно?

Решение

Я собираюсь предположить, что вы используете WebSockets или Socket.io. Поскольку вы реализуете игру, где верат задержки (и вы пометили его как таковые).

Я думаю, что сервер, вероятно, должен измерить и отслеживать это для каждого клиента.

Вы, вероятно, хотите реализовать какое-то действие Ping, что сервер может запросить клиента. Как только клиент получает запрос, он отправляет ответ на сервер. Затем сервер делит на 2 и обновляет задержку для этого клиента. Вы, вероятно, хотите, чтобы сервер периодически делать это с каждым клиентом и, вероятно, в среднем последние несколько, чтобы вы не получили странное поведение от внезапных, но временных шипов.

Затем, когда есть сообщение от одного клиента, который необходимо отправить (или трансляцию) другому клиенту, сервер может добавить задержку Client1 на задержку Client2 и сообщить об этом в качестве задержки задержки Client2 в качестве части сообщения. Client2 будет знать, что событие на Client1 произошло, что многие миллисекунды назад.

Дополнительная причина для этого на сервере состоит в том, что некоторые временные метки JavaScript браузера неточно: http://ejohn.org/blog/accuracy-of-javascript-time/. Отказ Я подозреваю, что Timestamps Node.js так же точны (или более), чем V8 (что является одним из немногих точных).

Другие советы

Обзор:

После создания соединения Socket.IO вы создаете новый Date Объект на клиенте, давайте назовем это startTime. Отказ Это ваш начальное время прежде чем сделать запрос на сервер. Ты тогда выделяешь ping событие от клиента. Конвенция именования полностью зависит от вас. Между тем сервер должен слушать ping событие, и когда он получает ping, это немедленно излучает pong мероприятие. Клиент затем ловит pong мероприятие. В это время вы хотите создать еще один объект даты, который представляет Date.now(). Отказ Таким образом, в этот момент у вас есть две объекты даты - начальная дата, прежде чем сделать запрос на сервер, а другой объект даты после того, как вы сделаете запрос на сервер, и он ответил. Вычтите startTime из текущего времени, и у вас есть latency.

Клиент

var socket = io.connect('http://localhost');
var startTime;

setInterval(function() {
  startTime = Date.now();
  socket.emit('ping');
}, 2000);

socket.on('pong', function() {
  latency = Date.now() - startTime;
  console.log(latency);
});

Сервер

io.sockets.on('connection', function (socket) {
  socket.on('ping', function() {
    socket.emit('pong');
  });
});

Также доступно как Github Gist.

Что я обычно делаю, чтобы отправить меток времени с запросом:

  1. На клиенте создайте new Date() и отправить timestamp: date.getTime() на сервер, с каждым запросом JSON.
  2. На сервере, при получении запроса, положите processed: (new Date()).getTime() в объекте.
  3. Обрабатывать запрос.
  4. На ответ, положите timestamp По запросу и новое обрабатываемое поле: processed: (new Date()).getTime() - req.processed Теперь содержит количество миллисекундов, которые нужно было обработать запрос.
  5. На клиенте, при получении ответа, возьмите timestamp (что то же самое, что было отправлено на PT 1) и вычтите его из текущего времени и вычтите время обработки (processed), и есть твое «реальное» время пинга в миллисекундах.

Я думаю, что вы всегда должны включать время для запроса, так и для реагирования в времени Ping, даже если есть одностороннее общение. Это связано с тем, что это стандартное значение «время пинга» и «латентность». И если это одностороннее общение, и задержка - это только половина настоящего времени Пинг, это просто «хорошая вещь».

После прочтения всех этих ответов ...

... Я все еще не был удовлетворен. Я посетил официальные документы и хорошо, ну, хорошо - решение уже встроено.

Вам просто нужно это реализовать - проверить мою:

Клиент

// (Connect to socket).

var latency = 0;

socket.on('pong', function(ms) {
    latency = ms;

    console.log(latency);
});

// Do cool things, knowing the latency...

Сервер

var server = require('http').Server(app);

// "socket.io": "^1.7.1"
// Set pingInterval to whatever you want - 'pong' gets emitted for you!
var io = require('socket.io')(server, {pingInterval: 5000});

Вот мой действительно быстрый и грязный скрипт, чтобы проверить пинг ... просто отправиться в http: // yourserver: 8080 В вашем браузере и посмотрите консоль (SSH Terminal для меня).

var http = require('http');
var io = require('socket.io');

server = http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write('<html>\n');
  res.write('  <head>\n');
  res.write('    <title>Node Ping</title>\n');
  res.write('    <script src="/socket.io/socket.io.js"></script>\n');
  res.write('    <script>\n');
  res.write('        var socket = new io.Socket();\n');
  res.write('        socket.on("connect",function(){ });\n');
  res.write('        socket.on("message",function(){ socket.send(1); });\n');
  res.write('        socket.connect();\n');
  res.write('    </script>\n');
  res.write('  </head>\n');
  res.write('  <body>\n');
  res.write('    <h1>Node Ping</h1>\n');
  res.write('  </body>\n');
  res.write('</html>\n');
  res.end();
});
server.listen(8080);

console.log('Server running at http://127.0.0.1:8080/');

var socket = io.listen(server);

socket.on('connection',function(client){
  var start = new Date().getTime();
  client.send(1);
  client.on('message',function(message){ client.send(1);  console.log( new Date$
  client.on('disconnect',function(){});
});

Мне очень интересно, потому что кажется, что мои пинги довольно высоки (отключение на руке 200-400 мс) на больших ящиках VPS с выделенными ресурсами как в Калифорнии, так и в Нью-Джерси. (Я на восточном побережье), я делаю ставку, просто много задержки на ящиках VPS B / C, они служат столько трафика?

То, что заставляет меня, так это то, что обычный пинг из терминала Linux с того же клиента на тот же сервер - это 11 мс в среднем, в среднем 10-м коэффициентом 10 ниже ... Я делаю что-то не так или нечто медленно с Node.js / розетку. IO / Websockets?

Читать первым - Из-за повторных вопросов, почему это должно работать, позвольте мне немного уточнить.

  • Функция обратного вызова клиента выполнено на клиенте, Вот почему он имеет доступ к закрытию, включая start переменная, содержащая метку времени. Это Аргумент ACK () в Socket.IO.
  • Сервер естественно не может вызвать произвольную функцию на клиенте и получить доступ к закрытию функции. Но socket.io Позволяет определить обратный вызов, который кажется, кажется выполненным На сервере, но на самом деле это просто передает аргументы функции через веб-сокет, и клиент затем вызывает обратный вызов.

Что происходит ниже (пожалуйста, проверьте пример код!):

  1. Клиент хранит текущий момент времени 1453213686429 в start
  2. Клиент отправляет А. ping событие на сервер и ждет ответа
  3. Сервер отвечает на событие Ping с «Пожалуйста, позвоните в обратный вызов с пустыми аргументами»
  4. Клиент получает ответ и звонки clientCallback с пустыми аргументами (проверьте демонстрационный код, если вы хотите увидеть аргументы)
  5. clientCallback снова принимает текущий момент времени на клиенте, например, 1453213686449, и знает, что 20 ms прошло с тех пор, как он отправил запрос.

Представьте себе друид (Клиент) удерживая секундомер и нажатие кнопки, когда посланник (мероприятие) Начинает бегать и нажать его снова, когда посланник прибывает со своим прокруткой (функциональные аргументы). Отказ Затем друид читает прокрутки и добавляет имена ингредиентов в его рецепт зелья и заваривает зелье. (Перезвоните)

Хорошо, забудьте предыдущий абзац, думаю, вы получили точку.


Хотя вопрос уже ответил, здесь краткосрочная реализация для проверки RTT с socket.io:

Клиент

var start = Date.now();
this.socket.emit( 'ping', function clientCallback() {
    console.log( 'Websocket RTT: ' + (Date.now() - start) + ' ms' );
} );

Сервер

socket.on( 'ping', function ( fn ) {
    fn(); // Simply execute the callback on the client
} );

Демо-код

Демо-код как модуль узла: Socketio-callback.tgz. Установите его и запустите его

npm install
node callback.js

а затем перейти к http: // localhost: 5060

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top