2
0

More than 3 years have passed since last update.

httpとwebsocketの兼用(統合)サーバーを作る

Last updated at Posted at 2020-08-30

一例です。

前準備

前提・環境

  • node.js: v10.16.0(async/awaitをサポートしている程度のバージョン)
  • npm: v6.14.2(上のnode.jsとマッチするバージョンであればOK)
  • windows 10 64bit

※ async/awaitは簡易化のために使用してるだけなので、必須ではないです。

ディレクトリ構造

[ルートフォルダ]
|- public
  |- index.html
|- utils
  |- getLocalIp.js
|- server.js
|- …その他package.json等

依存モジュールのインストール

npm i node-static ws

サーバー側

/server.js
const { createServer } = require("http");
const { Server: FileServer } = require("node-static");
const { Server: WebSocketServer } = require("ws");
const getLocalIp = require("./utils/getLocalIp");

const PORT_NUM = 8080;

(async () => {
  // ローカルipアドレス取得
  const host = await getLocalIp().catch((err) => {
    throw err;
  });

  // httpサーバー立ち上げ
  const fileServer = new FileServer(`${__dirname}/public`);
  const server = createServer((request, response) => {
    request
      .addListener("end", function () {
        fileServer.serve(request, response);
      })
      .resume();
  });

  // websocketサーバー立ち上げ(兼用)
  const wsServer = new WebSocketServer({
    server: server,
  });

  // クライアントとの接続確立後
  wsServer.on("connection", (ws) => {
    ws.on("message", (message) => {
      console.log("Received: " + message);

      if (message === "hello") {
        ws.send("hello from server!");
      }
    });
  });

  // サーバーリッスン
  server.listen(PORT_NUM, host);
  server.on("listening", () => {
    // 準備完了でコンソールにURL表示
    const addressInfo = server.address();
    console.log(`http://${addressInfo.address}:${addressInfo.port}`);
  });
})();

/utils/getLocalIp.js
/**
 * ローカルipアドレスを取得。非同期
 * @see https://stackoverflow.com/a/9542157
 */
module.exports = function () {
  return new Promise((resolve, reject) => {
    require("dns").lookup(require("os").hostname(), (
      error,
      address
    )=> {
      if (error) {
        reject(error);
        return;
      }
      resolve(address);
    });
  });
};

クライアント側

/public/index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Websocket sample</title>
  </head>

  <h1>Websocket sample</h1>
  <body>
    <script>
      // URLがそのままwsとのコネクション用アドレスになる
      const { host, pathname, protocol } = window.location;
      const wsProtocol = protocol === "http:" ? "ws://" : "wss://";
      const address = wsProtocol + host + pathname;
      const socket = new window.WebSocket(address);

      // サーバーからのデータ
      socket.onmessage = (res)=> {
        if (typeof res.data === 'string') {
          alert(`Message from server: ${res.data}`)
        }
      };

      // コネクション確立後
      socket.onopen = () => {
        // メッセージ送ってみる
        socket.send('hello')
      }
    </script>
  </body>
</html>

サーバー起動

node server.jsで起動して、ターミナルに表示されるURLにアクセスするとalertでメッセージが表示される…はず。

おまけ:サーバーを閉じたいとき

サーバーを閉じる際はwebsocketサーバーだけではなく、大元のhttpサーバーのほうも閉じる必要があるようです。

Close the HTTP server if created internally, terminate all clients and call callback when done. If an external HTTP server is used via the server or noServer constructor options, it must be closed manually.
https://github.com/websockets/ws/blob/HEAD/doc/ws.md#serverclosecallback

/server.js
wsServer.close();
server.close();

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0