كيف يمكنني أن أجد وقت الاستجابة (الكمون) من عميل في NodeJS مع مآخذ (مأخذ.io)?

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

سؤال

أنا في محاولة لخلق لعبة متعددة اللاعبين مع NodeJS وأريد أن مزامنة العمل بين العملاء.

ما يمكن أن يكون أفضل طريقة للعثور على الكمون (الوقت الذي طلب اتخاذ العودة إلى العميل) بين العميل و الخادم ؟

كانت فكرتي الأولى أن العميل رقم 1 يمكن إرسال الزمني مع الطلب ، حتى عندما يكون العميل رقم 2 سوف تحصل على عمل العميل رقم 1 هو ضبط العمل بسرعة لإزالة تأخير الطلب.ولكن المشكلة هي أنه ربما تاريخ النظام وقت من اثنين من عملاء ليست متطابقة لذلك ليس من الممكن اثنين أعرف بكرة تأخير بناء على طلب العميل رقم 1.

الحل الآخر هو استخدام الطابع الزمني الخادم, ولكن الآن كيف يمكن أن أعرف من الكمون عميل ؟

هل كانت مفيدة؟

المحلول

أنا ذاهب لنفترض أنك تستخدم WebSockets أو المقبس.IO منذ كنت في تنفيذ لعبة حيث الكمون المسائل (وأنت معلم على هذا النحو).

أعتقد الخادم ربما ينبغي قياس وتتبع هذا لكل عميل.

ربما كنت ترغب في تنفيذ بعض نوع من بينغ العمل يمكن طلب العميل.حالما يتلقى العميل على طلب يرسل استجابة مرة أخرى إلى الخادم.الملقم ثم يقسم بنسبة 2 والتحديثات الكمون لهذا العميل.ربما كنت تريد الخادم أن تفعل هذا بشكل دوري مع كل عميل و ربما المتوسط الماضي عدة حتى أن كنت لا تحصل على سلوك غريب من المفاجئ ولكن المؤقتة المسامير.

ثم, عندما يكون هناك رسالة من عميل واحد التي تحتاج إلى إرسالها (أو البث) إلى آخر عميل الملقم يمكن إضافة client1 الكمون إلى client2 الكمون و التواصل هذا الكمون الإزاحة إلى client2 كجزء من الرسالة.client2 ثم سوف تعرف أن هذا الحدث على client1 حدث أن العديد من ميلي ثانية واحدة.

سبب إضافي للقيام بذلك على الخادم أن بعض متصفح جافا سكريبت الطوابع الزمنية غير دقيقة: http://ejohn.org/blog/accuracy-of-javascript-time/.وأظن 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');
  });
});

متاح أيضا ك جيثب جوهر.

ما أفعله عادة لإرسال الطابع الزمني مع الطلب:

  1. على العميل ، قم بإنشاء أ new Date() وإرسال timestamp: date.getTime() إلى الخادم ، مع كل طلب JSON.
  2. على الخادم ، عند تلقي طلب ، ضع أ processed: (new Date()).getTime() في الكائن.
  3. طلب التعامل.
  4. على الرد ، ضع timestamp من الطلب ، وحقل جديد معالجته: processed: (new Date()).getTime() - req.processed هذا يحتوي الآن على عدد المللي ثانية التي استغرقها لمعالجة الطلب.
  5. على العميل ، عند تلقي استجابة ، خذ timestamp (وهو نفسه الذي تم إرساله على حزب العمال 1) وطرحه من الوقت الحالي ، وطرح وقت المعالجة (processed) ، وهناك وقت ping "الحقيقي" في مللي ثانية.

أعتقد أنه يجب عليك دائمًا تضمين الوقت للطلب والاستجابة في وقت Ping ، حتى لو كان هناك اتصال في اتجاه واحد. هذا لأن هذا هو المعنى القياسي وراء "وقت ping" و "الكمون". وإذا كان التواصل في اتجاه واحد والكمون هو نصف وقت 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});

هيريس بلدي حقا سريعة وقذرة النصي إلى اختبار ping ...الرأس فقط http://yourserver:8080 في المتصفح الخاص بك ومشاهدة وحدة التحكم (ssh محطة بالنسبة لي).

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-400ms ذهابا وإيابا) على vps صناديق w/ تخصيص الموارد على حد سواء في كاليفورنيا ونيو جيرسي.(أنا على الساحل الشرقي) أراهن أن هناك الكثير من الكمون على vps مربعات ب/ج انهم يقدمون الكثير من حركة المرور ؟

الشيء الذي يحصل لي هو أن العادي بينغ من محطة طرفية لينكس من نفس العميل إلى الملقم نفسه هو 11ms على متوسط عامل من 10 أقل ...أفعل شيئا خاطئا أو هو شيء بطيء مع عقدة.js/مأخذ.io/websockets?

اقرأ اولا - بسبب الأسئلة المتكررة لماذا من المفترض أن يعمل هذا ، اسمحوا لي أن أوضح قليلاً.

  • وظيفة رد اتصال العميل هي نفذ على العميل ، وهذا هو السبب في أنه يمكنه الوصول إلى الإغلاق ، بما في ذلك start متغير يحتوي على الطابع الزمني. هذا هو حجة ACK () في socket.io.
  • لا يمكن للخادم بطبيعة الحال استدعاء وظيفة تعسفية على العميل والوصول إلى إغلاق الوظيفة. ولكن socket.io يسمح بتحديد الترون المستدعي ، الذي يبدو أنه تم تنفيذه بواسطة الخادم ، ولكن هذا في الواقع يمرر وسيطات الوظيفة من خلال مقبس الويب ، ثم يقوم العميل باستدعاء رد الاتصال.

ماذا يحدث أدناه (يرجى التحقق من رمز المثال!):

  1. يقوم العميل بتخزين الطابع الزمني الحالي 1453213686429 في start
  2. العميل يرسل ping حدث للخادم وينتظر إجابة
  3. يستجيب الخادم لحدث Ping بـ "يرجى الاتصال على رد الاتصال الخاص بك مع وسيطات فارغة"
  4. يتلقى العميل الاستجابة والمكالمات clientCallback مع الوسائط الفارغة (تحقق من الرمز التجريبي إذا كنت تريد رؤية الوسائط)
  5. clientCallback مرة أخرى يأخذ الطابع الزمني الحالي على العميل, ، على سبيل المثال 1453213686449, ويعرف ذلك 20 ms مرت منذ أن أرسلت الطلب.

تخيل الدرويد (عميل) عقد ساعة توقيت ودفع الزر عند الرسول (حدث) يبدأ الركض ، ودفعه مرة أخرى عندما يصل الرسول مع التمرير الخاص به (حجج الوظيفة). ثم يقرأ Druid التمرير ويضيف أسماء المكونات إلى وصفة الجرعة الخاصة به ويخمر الجرعة. (أتصل مرة أخرى)

حسنًا ، ننسى الفقرة السابقة ، أعتقد أنك حصلت على هذه النقطة.


على الرغم من أن السؤال قد تمت الإجابة عليه بالفعل ، إلا أنه هنا تطبيق قصير للتحقق من 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