node.js - UDP 请求未连接到 repl.it 服务器
问题描述
我正在尝试使用 node.js 和 repl.it 上的数据报编写一个简单的 UDP 服务器,但我无法连接到服务器,我尝试了不同的端口,但没有建立任何连接。在服务器上运行“npm start”后,我得到:服务器正在侦听 0.0.0.0:3000 仅此而已,这似乎是什么问题?该代码在本地服务器上运行良好,建立了连接并发送了数据包,但是当我尝试在 repl.it 上运行它时没有任何反应。
const _ = require('lodash');
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const serverConfig = {
welcome: 'Welcome to the game!',
serverPort: 3000, //heroku server port!
clientPort: 6510,
sendingInterval: 500, //msec
inactivityCheckInterval: 30, //sec
pingAfter: 60, //sec
deactivateAfter: 150, //sec
debug: true
}
const users = [];
const messages = [];
const outerQueue = [];
const gameSlots = [0,0,0,0,0,0,0,0];
const gameSlotsNumber = [2,2,2,4,4,4,6,6];
const scheduleQueue = () => setTimeout(processQueue, serverConfig.sendingInterval);
const debug = txt => { if (serverConfig.debug) console.log(txt) };
const processQueue = () => {
if (outerQueue.length > 0) {
const m = outerQueue.shift();
//console.log(m);
server.send(m.body, m.port, m.address, scheduleQueue);
} else {
scheduleQueue();
}
}
const setName = (rinfo, name) => {
debug(`Auth request from ${rinfo.address}:${rinfo.port}`);
if (nameInUse(name)) {
addToQueue(`<M${String.fromCharCode(0)} >** Name in use. Type /nick to set new one`, rinfo.port, rinfo.address);
} else {
addToQueue(`<M${String.fromCharCode(1)} >** Authorization OK`, rinfo.port, rinfo.address);
addToQueue(`<A >${name}`, rinfo.port, rinfo.address);
const user = getUser(rinfo);
if (user) {
user.name = name;
registerUserAction(user);
debug(`Name updated`);
} else {
const gmSlot = 20; //out of regular 8 slots
users.push({
address: rinfo.address,
port: rinfo.port,
name: name,
lastAction: nowStamp(),
gameSlot: gmSlot,
active: true
})
debug(`User Added`);
}
broadcastStatus();
}
}
const parseDatagram = (msg, rinfo) => {
msg = msg || '';
const header = getHeader(msg);
if (validateHeader(header)) {
switch (header.command) {
case 'S': // status
sendStatus(rinfo);
break;
case 'A': // auth
setName(rinfo, header.body);
break;
case 'M': // message
sendMessage(rinfo, header);
break;
// case 'C': // command
// runCommand(rinfo, header);
// break;
case 'P': // ping
const user = getUser(rinfo);
if (user) registerUserAction(user);
break;
case 'O': //set gameslot of the user
setUserSlot(rinfo,header.body); //first byte of the message is the number of the slot
checkForFullSlots(rinfo);
broadcastUsersInSlots();
break;
case 'X': //player lost the battle
const user2 = getUser(rinfo);
playerLost(rinfo,user2); //first byte of the message is the number of the slot
break;
case 'Q': //lost player quit the game
const user3 = getUser(rinfo);
playerQuitGame(user3);
break;
}
} else {
debug(`Invalid header: ${msg} from ${rinfo.address}:${rinfo.port}`);
}
}
const sendStatus = rinfo => {
debug(`Status request from ${rinfo.address}:${rinfo.port}`);
const user = getUser(rinfo);
addToQueue(`<S${String.fromCharCode(user && user.active?1:0)}${String.fromCharCode(getActive().length)}>${serverConfig.welcome}`, rinfo.port, rinfo.address);
if (user && user.active)
addToQueue(`<A >${user.name}`, rinfo.port, rinfo.address);
}
const sendMessage = (rinfo, header) => {
debug(`Message from ${rinfo.address}:${rinfo.port}: ${header.body}`);
const user = getUser(rinfo);
if (user) {
broadcast(`<M ><${user.name}>${header.body}`);
registerUserAction(user);
debug(`Message broadcasted`);
} else {
addToQueue(`<M >** Unauthorized. Type /nick to set name.`, rinfo.port, rinfo.address);
}
}
const setUserSlot = (rinfo,slotAndUser) => {
const user = getUser(rinfo)
if(user){
user.gameSlot = slotAndUser.msg[5]; //after 4 byte header
}
}
const broadcast = msg => {
_.each(users, user => {
if (user.active) {
addToQueue(`${msg}`, user.port, user.address);
}
});
}
const playerQuitGame = (user) => {
if(user){
user.gameSlot = 20; //after 4 byte header
}
broadcastUsersInSlots();
}
const playerLost = (rinfo,msx,user) => {
if(user){
_.each(users,usr => {
if(user.gamePort == usr.gamePort) addToQueue(`<X >${user.name}`, usr.port, usr.address);
});
}
}
const addToQueue = (bodyy, portt, addresss) => outerQueue.push({body:bodyy, port: serverConfig.clientPort,address: addresss});
const checkForFullSlots = (rinfo) => {
countSlots();
for(var x=0;x<8;x++){
if(gameSlots[x]==gameSlotsNumber[x]){
broadcastBegin(x); //B->begin the game in the slot
}
}
}
const countSlots = () => {
const slots = [0,0,0,0,0,0,0,0];
_.each(users, user => {
if(user.gameSlot<8) //number f slots equals 8;
slots[user.gameSlot]++;
});
gameSlots = slots;
}
const broadcastBegin = slot => {
_.each(users, user => {
if(user.active && user.gameSlot== slot) {
addToQueue(`<B >game started, place your ships!`, user.port, user.address);
}
});
}
const getHeader = msg => {
const msg8 = Uint8Array.from(msg)
return {
h1: String.fromCharCode(msg[0]), //"<"
command: String.fromCharCode(msg[1]),
paramL: msg8[2],
paramH: msg8[3],
h2: String.fromCharCode(msg[4]), //">"
body: msg.toString().substring(5)
}
}
const validateHeader = header => {
return (header.h1 == '<') && (header.h2 == '>')
}
const getUser = rinfo => _.find(users, {'address': rinfo.address});
const getActive = () => _.filter(users, {'active': true});
const broadcastUsersInSlots = () => {
var usersNames = ["","","","","","","",""];
for(var i=0;i<8;i++){
_.each(users, user => {
if(user.gameSlot == i){
usersNames[i]+=user.name+"|||";
}
});
}
_.each(users, user => {
if (user.active && user.gameSlot <8) {
var msx = usersNames[user.gameSlot];
if(msx==""){
msx="empty";
}
addToQueue(`<Y >${msx}`, user.port, user.address); //Y equals total users in slots
}
});
broadcastGameSlots();
}
const broadcastGameSlots = () => {
_.each(users, user => {
if(user.active && user.gameSlot > 7) {
addToQueue(`<W >${gameSlots[0]}${gameSlots[1]}${gameSlots[2]}${gameSlots[3]}${gameSlots[4]}${gameSlots[5]}${gameSlots[6]}${gameSlots[7]}`,
user.port,user.address);
}
});
}
const broadcastShipsUser = (rinfo,userSending,msx) => {
_.each(users, user => {
if(userSending.gameSlot == user.gameSlot){
addToQueue(`<Z >${msx.body}`, user.port, user.address); //Z equals new ships set by the user, 2 bytes-X,Y pos, 3rd byte-rotation
}
});
userSending.status = 1; //ships have been set
}
const broadcastShot = (userSending, msx) => { // msx contains 2 bytes: x position of the bullet, y position of the bullet
_.each(users, user => {
if(userSending.gameSlot == user.gameSlot){
addToQueue(`<R >${userSending.name}|||${msx}`,user.port,user.address);
}
});
}
const broadcastStatus = msg => {
_.each(users, user => {
if (user.active) {
addToQueue(`<S ${String.fromCharCode(getActive().length)}>`, user.port, user.address);
}
});
}
const traceInactivity = () => {
const now = nowStamp();
_.each(users, user => {
if (user.active) {
if (now - user.lastAction > serverConfig.pingAfter) {
pingUser(user);
};
if (now - user.lastAction > serverConfig.deactivateAfter) {
registerUserAction(user, false);
user.gameSlot= 20;
broadcastUsersInSlots();
debug(`deactivated user ${user.name}`);
broadcastStatus();
};
};
});
setTimeout(traceInactivity, serverConfig.inactivityCheckInterval * 1000);
}
const pingUser = user => {
debug(`Pinging user: ${user.name}`);
addToQueue(`<P >PING!`, user.port, user.address);
}
const nameInUse = name => _.find(users, {'name': name, 'active': true});
const registerUserAction = (user, active = true) => {
user.lastAction = nowStamp();
user.active = active;
}
const nowStamp = () => Math.floor(Date.now() / 1000);
server.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
server.on('message', (msg, rinfo) => {
debug(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
parseDatagram(msg, rinfo);
});
server.on('listening', () => {
const address = server.address();
console.log(`server listening ${address.address}:${address.port}`);
});
server.bind(serverConfig.serverPort);
scheduleQueue();
traceInactivity();
解决方案
推荐阅读
- java - 如何在 JPAQuery 中使用 INNER JOIN?
- mysql - MYSQL - 在表中使用 AFTER UPDATE 进行内部联接
- jquery - 如何使用 JQuery 将评论部分的评论推送到数组中?
- python - 从不同大小的数组中采样每个第 n 个值 Python
- java - Java中的List.of()生成什么类型的列表
- grpc - 为什么 grpc-web 需要特使代理?
- node.js - 邮递员请求收到 HTTP 401 状态代码
- xamarin.forms - Xamarin 模拟时钟通过以下手指手势旋转句柄
- sql - 为什么在 MS Access 中运行更新查询时要求“输入参数值”?
- list - 当子元素是字典时,with_subelements