javascript dgram节点中的UDP pinger超时

问题描述

因此,对于我正在学习的课程,我们正在使用Node.js和Dgram用Javascript编码UDP pinger。我们得到了以下任务:

为应用程序创建客户端代码。您的客户端应向目标UDP服务器发送10条ping消息。对于每条消息,您的客户应计算从发送包裹到收到响应的往返时间。如果一路上丢了包裹,客户也要处理。这应通过在发送每个数据包后让客户端等待1秒钟的响应来完成。如果未收到答复,则客户端应进行相应的日志记录(程序包丢失,无响应,超时等),并发送新的程序包以重试。但是,发送的软件包总数仍应仅为10。客户端还应计算丢失的软件包/未收到响应的百分比,并在关闭连接之前记录该百分比。

这是正确的做法,我认为是这样。我已经编码了一段时间了,我差不多要完成了,但是在使客户端发送程序包,等待响应然后采取相应措施方面存在问题。

到目前为止,我的代码所做的基本上是发送ping,并且在收到pong时,它将发送另一个ping。我不知道的是如何在发送下一个包之前使它记录未收到响应。换句话说,我知道如何使它对收到的响应做出反应,如果在设定的时间范围内未给出响应,我只是不知道如何使它做出响应。我已经尝试过使用if语句和循环以及异步函数,但是我还没有使它起作用,所以现在我要寻求帮助。

代码在这里

const dgram = require("dgram");
const ms = require("ms"); 

var client = dgram.createSocket("udp4");


const PORT = 8000;
const HOST = "localhost";

let today = "";
let t0 = "";
let t1 = "";
let RTT = "";

let sentPackages = "";
let receivedPackages = "";

const messageOutbound = Buffer.from("You Up?");

sendPackage();

const x = setInterval(sendPackage,1000);
client.on("message",(message,remote) => {
    receivedPackages++
    today = new Date();
    t1 = today.getTime();
    console.log(
      `Message from: ${remote.address}:${remote.port} saying: ${message}`
    );
    RTT = ms(t1 - t0,{ long: true });
    console.log(RTT);
    const x = setInterval(sendPackage,1000);
  });

client.on('error',(err) => {
  console.log(`server error:\n${err.stack}`);
  server.close();
});  

async function sendPackage() {
  if (sentPackages < 10) {
    client.send(messageOutbound,messageOutbound.length,PORT,HOST,() => {
      sentPackages++
      let today = new Date();
      t0 = today.getTime();
      console.log(
        `message has been sent to ${HOST}:${PORT}. Message sent at: ${t0}`
      );
    });
  } else {
    calculateLoss();
    client.close();
  }
};
function calculateLoss() {
  let amountLost =  sentPackages - receivedPackages;
  let percentageLoss = amountLost / sentPackages * 100
  console.log(amountLost);
  console.log(percentageLoss +"% of packages lost");
};

解决方法

我将使用async / await在消息之间简单地等待1000ms / 1s,然后跟踪数组中的所有消息。

我们用uuid标识邮件,因此我们可以确保收到的邮件与我们发送的邮件匹配。

然后我们可以记录所有必需的统计信息:

const dgram = require("dgram");
const uuid = require('uuid');

const PORT = 8000;
const HOST = "localhost";

const client = dgram.createSocket("udp4");

// Array that keeps track of the messages we send
let messages = [];

// When we get a message,decode it and update our message list accordingly...
client.on("message",(messageBuffer,remote) => {
    let receivedMessage = bufferToMessage(messageBuffer);
    // Find the message we sent and set the response time accordingly.
    let message = messages.find(message => message.uuid === (receivedMessage ||{}).uuid);
    if (message) {
        message.responseTimestamp = new Date().getTime();
    }
});

client.on('error',(err) => {
    console.log(`server error:\n${err.stack}`);
    server.close();
});  

function createMessage() {
    return { uuid: uuid.v4() };
}

function messageToBuffer(message) {
    return Buffer.from(JSON.stringify(message),"utf-8");
}

function bufferToMessage(buffer) {
    try {
        return JSON.parse(buffer.toString("utf-8"));
    } catch (error) {
        return null;
    }
}

// Wait for timeout milliseconds
function wait(timeout) {
    return new Promise(resolve => setTimeout(resolve,timeout));
}

function sendMessage(message,port,host) {
    // Save the messages to our list...
    messages.push(message);
    console.log(`Sending message #${messages.length}...`);
    // Set the time we send out message...
    message.sentTimestamp = new Date().getTime();
    let messageBuffer = messageToBuffer(message);
    return new Promise((resolve,reject) => {
        client.send(messageBuffer,messageBuffer.length,host,(error,bytes) => {
            if (error) {
                reject(error);
            } else {
                resolve(bytes);
            }
        })
    });      
}

async function sendMessages(messageCount,timeout) {
    for(let messageIndex = 0; messageIndex < messageCount; messageIndex++) {
        let message = createMessage();
        await sendMessage(message,host);
        await wait(timeout);
        if (message.responseTimestamp) {
            console.log(`Response received after ${message.responseTimestamp - message.sentTimestamp} ms...`);
        } else {
            console.log(`No response received after ${timeout} ms...`);
        }
    }
    logStatistics(messages);
}

function logStatistics(messages) {
    let messagesSent = messages.length;
    let messagesReceived = messages.filter(m => m.responseTimestamp).length;
    let messagesLost = messagesSent - messagesReceived;
    console.log(`Total messages sent: ${messagesSent}`);
    console.log(`Total messages received: ${messagesReceived}`);
    console.log(`Total messages lost: ${messagesLost} / ${(100*messagesLost / (messages.length || 1) ).toFixed(2)}%`);
    if (messagesReceived > 0) {
        console.log(`Average response interval:`,messages.filter(m => m.responseTimestamp).reduce((averageTime,message) =>  {
            averageTime += (message.responseTimestamp - message.sentTimestamp) / messagesReceived;
            return averageTime;
        },0) + " ms");
    }
}

sendMessages(10,PORT,HOST,1000);