问题描述
我制作了一个节点服务器,它通过 udp 连接返回服务器响应。
服务器响应和 udp 连接是通过 serverQuery 类处理的。我的问题是没有用于 UDP 连接的 await 命令,当我从服务器获得响应时我没有。所有服务器响应都被推送到一个数组 (responseArr),然后该数组被发送到响应对象。但是,当我发送响应对象时,它总是作为一个空数组出现,因为在代码执行时服务器还没有响应。
非常感谢您对此的任何见解。另外,请随时对我的代码提供反馈,因为我还是编程新手,谢谢!
index.js:
const fs = require('fs');
const express = require('express');
const serverQuery = require('./serverQuery');
PORT = process.env.PORT || 3000;
var app = express();
app.get('/api/serverlist/getstatus/:port/:host',(req,res) => {
requestObj = [
{
"host": req.params.host,"port": +req.params.port
}
];
let response = new serverQuery(requestObj,'getstatus',res);
});
app.get('/api/serverlist',res) => {
var data = fs.readFileSync('servers.json','utf8');
var obj = JSON.parse(data);
for (server in obj) {
new serverQuery(host,port,res,true);
}
// new serverQuery(host,res);
});
app.get('/api/serverlist/getinfo/:port/:host','getinfo',res);
res.send(response.responseArr);
});
app.listen(PORT,() => {
log(`Server running on port: ${PORT}`);
});
function log (ref) {
console.log(ref);
}
serverQuery.js
const Dgram = require('dgram');
const EventEmitter = require('events');
class ServerQuery extends EventEmitter {
// PROBLEM: UDP has no await/async functionality.
// How to return array of serverinfo when server response
// is not instantaneous?
// Test server: 35.194.92.249:29071
#cmdPrefix = Buffer.from([0xFF,0xFF,0x02]);
#cmd = '';
constructor (servers,query,res) {
super();
this.responseStatus = {"error": 200,"description": "OK",host: "255.255.255.255",port: "55555"};
this.responseArr = [];
this.on('response',function (serverResponse,responseArr) {
responseArr.push(serverResponse);
log(responseArr); // working
});
this.on('send',function (responseArr) {
res.send(responseArr);
});
let isValidQuery = true;
if (query === 'getinfo') {
this.#cmd = Buffer.from('getinfo\n','binary');
} else if (query === 'getstatus') {
this.#cmd = Buffer.from('getstatus\n','binary');
} else {
let errResponse = this.getError('invalid_query');
this.responseArr.push(errResponse);
log(errResponse);
res.send(this.responseArr);
isValidQuery = false;
}
if (isValidQuery) {
for (let server of servers) {
let validatePort = this.validate(server.port,'port');
let validateHost = this.validate(server.host,'ip');
if (validatePort.isValid && validateHost.isValid) {
this.newUDPConnection(server.host,server.port,this.responseArr);
} else {
this.responseArr.push(this.getError('invalid_address',server.host,server.port));
}
}
log(this.responseArr); // is getting executed before response emit
this.emit('send',this.responseArr);
}
}
newUDPConnection (host,responseArr) {
const udp = Dgram.createSocket('udp4');
var closeUDP = setTimeout(() => {
udp.close();
this.emit('response',this.getError('server_timeout',host,port),responseArr);
},1000);
udp.on('message',(msg,rinfo) => {
let serverResponse = this.statusResponseHandler(msg,rinfo);
this.emit('response',serverResponse,responseArr);
udp.close();
clearTimeout(closeUDP);
})
udp.send([this.#cmdPrefix,this.#cmd],(err) => {
if (err) {
log(err);
udp.close();
} else {
log(`Query: ${this.#cmdPrefix.toString() + this.#cmd.toString()}Address: ${host}:${port}`);
}
});
}
validate(refVar,varType) {
let isValid = false;
let status = "INVALID ParaMETERS";
if (varType != 'port' && varType != 'ip') {
console.log('INVALID ParaMETERS');
return;
}
if (varType == 'port') {
if (+refVar > 0 && +refVar < 65536) {
isValid = true;
status = "OK";
} else {
status = "INVALID";
}
}
if (varType == 'ip') {
if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(refVar)) {
isValid = true;
status = "OK";
} else {
status = "INVALID";
}
}
return {'isValid': isValid,'status': status};
}
statusResponseHandler (msg,rinfo) {
let returnObj = {};
// server address
const address = {"host": rinfo.address,"port": rinfo.port};
returnObj.address = address;
msg = msg.toString();
// remove colors
msg = msg.replace(/\^[0-9]/g,'');
// remove quotes
msg = msg.replace(/\"/g,'');
// remove special chars
msg = msg.replace(/[^\x00-\x7F]+/g,'');
// remove the '????statusResponse' from the server response
let msgArr = msg.slice(msg.indexOf('\\') + 1,msg.length).split("\\");
// convert array to an object with key value pairs
msgArr.forEach(function (a,i,aa) {
if (i & 1) {
returnObj[aa[i - 1]] = a;
}
});
// remove player info from the last key-value pair in the return object
let lastKey = Object.keys(returnObj)[Object.keys(returnObj).length-1];
let lastValue = returnObj[Object.keys(returnObj)[Object.keys(returnObj).length-1]];
returnObj[lastKey] = lastValue.slice(0,lastValue.indexOf('\n'));
// generate player info object and push to return object
returnObj.players = [];
let playeRSStr = lastValue.slice(lastValue.indexOf('\n') + 1,lastValue.length);
let playersArr = playeRSStr.split('\n');
playersArr.forEach(player => {
let playerInfo = player.split(' ',3);
if (!playerInfo[1]) {
// do nothing - this is to ignore empty player strings
} else {
returnObj.players.push({
"ping": playerInfo[1],"score": playerInfo[0],"name": playerInfo[2],"isBot": (+playerInfo[1] === 0) ? true : false
});
}
});
return returnObj;
}
createResponseStatus (err,desc,port) {
return {
"error": err,"desc": desc,"host": host,"port": port
}
}
getError (err,port) {
let errorObj = {
'invalid_address': this.createResponseStatus(422,`Invalid address`,'invalid_query': this.createResponseStatus(422,`Invalid query in serverQuery class constructor. Valid queries: \'getinfo\',\'getstatus\'`,'server_timeout': this.createResponseStatus(408,`Server timed out`,}
return errorObj[err];
}
}
function log (ref) {
console.log(ref);
}
module.exports = ServerQuery;
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)