Связь клиент-сервер в Node.js

Недавно я зашел на 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>
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
4 463
2

Ответы 2

Я бы использовал для этого веб-сокеты. После того, как вы установили соединение, вы можете отправлять сообщения с любой стороны. Пакет 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);
});

Другие вопросы по теме