Недавно я зашел на node.js, чтобы сделать онлайн-игру (для обучения). Читая различные руководства, я придумал простой код, показанный ниже. Имея код, я могу общаться между клиентом и сервером, а это почти все, что мне нужно для создания игры. Есть только одна проблема: только клиент может инициировать диалог, тогда как сервер может только отвечать. В дополнение к этому мне также нужно в любой момент отправить текущее состояние игры с сервера на клиент. Например, в игре для двоих, когда игрок отправляет команду, которая изменяет состояние игры, это новое состояние игры должно быть отправлено ОБОИМ игрокам.
Есть ли простой способ сделать это в node.js? Я знаю, что вы не можете просто отправить сообщение клиенту, поскольку нельзя ожидать, что клиент откроет порт для использования сервером, но, может быть, у клиента есть способ оставить соединение для использования сервером? Я из тех парней, которые учатся на примерах, поэтому хотелось бы получить какой-нибудь простой рабочий код.
Кстати, я размещаю игру на firebase, если это актуально.
index.js:
const functions = require('firebase-functions');
const express = require('express');
const app = express();
app.post('/game', (request, response) => {
request.body.randomNumber = Math.random();
console.info(request.body);
response.json(request.body);
});
exports.app = functions.https.onRequest(app);
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<input type = "text" id = "commandbox" onkeypress = "send(this)">
<br>
<div id = "display"></div>
<script>
const send = (ele) => {
if (event.key === 'Enter') {
console.info(ele.value);
const json = {
name: "John",
gender: "male",
age: 25,
message: ele.value
};
postToGame(json);
}
};
</script>
<script>
const postToGame = (json) => {
const xhr = new XMLHttpRequest();
xhr.open("POST", '/game', true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.onload = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("display").innerHTML = xhr.responseText;
}
};
xhr.send(JSON.stringify(json));
}
</script>
</body>
</html>





Я бы использовал для этого веб-сокеты. После того, как вы установили соединение, вы можете отправлять сообщения с любой стороны. Пакет WS npm делает это довольно просто.
Пример сервера (с использованием пакета ws npm):
const WebSocket = require('ws');
// Set up server
const wss = new WebSocket.Server({ port: 8080 });
// Wire up some logic for the connection event (when a client connects)
wss.on('connection', function connection(ws) {
// Wire up logic for the message event (when a client sends something)
ws.on('message', function incoming(message) {
console.info('received: %s', message);
});
// Send a message
ws.send('Hello client!');
});
Пример клиента (здесь нет необходимости в каком-либо пакете, он встроен в большинство браузеров):
// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:8080');
// Connection opened
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Listen for messages
socket.addEventListener('message', function (event) {
console.info('Message from server ', event.data);
});
Существуют альтернативы, если вы не можете использовать веб-сокеты, такие как опрос (когда клиент периодически вызывает сервер, чтобы узнать, есть ли сообщение) и длительный опрос (когда сервер удерживает HTTP-запрос открытым в течение искусственно длительного периода времени. пока сообщение не будет готово).
Еще одна альтернатива - база данных Firebase Realtime.
https://github.com/firebase/quickstart-js/blob/master/database/scripts/main.js
<!-- index.html file in client browser -->
<script src = "/__/firebase/5.5.0/firebase-app.js"></script>
<script src = "/__/firebase/5.5.0/firebase-auth.js"></script>
<script src = "/__/firebase/5.5.0/firebase-database.js"></script>
<script src = "/__/firebase/init.js"></script>
<script src = "scripts/main.js"></script>
<!-- main.js file in client browser -->
// Create new comment.
// createNewComment, commentInput, addCommentForm is defined in the main.js
addCommentForm.onsubmit = function(e) {
e.preventDefault();
createNewComment(postId, firebase.auth().currentUser.displayName, uid, commentInput.value);
commentInput.value = '';
commentInput.parentElement.MaterialTextfield.boundUpdateClassesHandler();
};
// Listen for comments.
// addCommentElement, postElement is defined in the main.js
var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', function(data) {
addCommentElement(postElement, data.key, data.val().text, data.val().author);
});