前回の続きを書いていく。
const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const PORT = 5000;
server.listen(PORT, () => console.log(`server is running on ${PORT}`));
この部分の解説をしていく。
const なになに という部分ではインストールしたモジュールをインスタンス化している。
インスタンス化は分かったつもりにはなるが意外と説明するのは難しい概念である。
一応、インスタンス化は何なのか調べてみる。
調べてみると、オブジェクト指向で出てくる表現の1つでクラスから実体を作ることと書かれている。
自分なりの噛み砕き方で説明するとクラスは汎用性高く書かれた設計図で色々な具体を当てはめることが出来る。
その具体化をする行為がインスタンス化であり、実際になにか処理を実行する際はインスタンス化した方が見やすくなるといったところであろうか。
初学者なので何か違う部分があれば指摘してほしい。
また、httpモジュールは初めからインストールされているのでインストールせずに使用することが出来る。
こうすることでサーバーを立ち上げている。
PORTではPORT番号を指定している。
socket.ioは自動的にクライアントにサービスを提供するため、モジュールを1つだけインストールすればよい。
便利なものである。
server.listen という表現はよく分からなかったので調べてみた。
このサイトによると、外部からの接続を待ち受けて応答するサーバソフトウェアは自分が通信したいポート番号をOSに登録してそのポートに接続要求があると通知を受けて処理を行う。
この動作のことを「ポートをリッスンする」のように表現している。
つまり、この記述がポート番号を指定して、リッスン状態にしている事がわかる。
そして、ここ記述を終えるとクライアントサイドとの送受信の記述をしていく。
基本的にonメソッドはデータを受け取る、emitメソッドはデータを送信することをいう。
そして、今回のクライアントはnext.jsを指している。
io.on("connection", (socket) => {
console.log("クライアントと接続しました!");
socket.on('disconnect', () => {
console.log('クライアントとの接続が切れました!');
});
});
第一引数に"connection"といれると接続したときの処理を記述できる。この場合、接続するとコンソールログの処理が行われる。また、接続した状態から"disconnect"状態になったらログの処理をするため"connection"の記述の中に"disconnect"の記述をしている。
次に、クライアント側の記述に移った。
クライアント側のファイルに移り、ターミナル上で
npm i socket.io-client
という記述をしていく。
これはサーバーとクライアントの通信するためのパッケージである。それをインストールした。
そして、以下の記述をするとクライアント側のサーバーが起動する。
npm run dev
localhost:3000とブラウザ上で入力するとclient上で設定した初期のアプリケーションが起動する。
import Head from 'next/head'
import Image from 'next/image'
import { Inter } from '@next/font/google'
import styles from '@/styles/Home.module.css'
import io from "socket.io-client";
const socket = io("http://localhost:5000");
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main><h1>Hello World!</h1></main>
</>
)
}
mainタブに書かれていた記述をすべて削除して、h1タブでHello World!と記述を入れると、
このようにきちんと表示される。
このボーダーみたいなやつはCSSファイルをみて該当のところの記述を削除すれば消えた。
クライアントとサーバーの通信を実現するために先程インストールしたsocket.io-clientを使用する必要がある。
ちなみに、socket.io-clientがきちんとインストールされたかどうかサーバー側のディレクトリの中のpackage.jsonファイルの中を確認する必要がある。
socket.io-clientを使用するために以下の記述をする必要がある。
import io from "socket.io-client";
const socket = io("http://localhost:5000");
io()の中にはサーバーサイドのURLを記述するがこのときPORT番号にズレが生じる。ブラウザで開いているPORT番号は3000番である。
そのため、CORSポリシーに引っかかりエラーが生じる。すなわち、クライアントとサーバーで上手く通信ができないのである。
CORS(クロス)とは、オリジン管理ソース共有と呼ばれるものである。
セキュリティ上の観点からポート番号が異なる場合それらの通信はできませんよというエラー。
これを解消するために明示的に通信を許可する記述をする必要がある。
socket.ioの公式ドキュメントでCORSと検索をかけるとその対処法が記述されている。
import { createServer } from "http";
import { Server } from "socket.io";
const httpServer = createServer();
const io = new Server(httpServer, {
cors: {
origin: "https://my-frontend.com",
// or with an array of origins
// origin: ["https://my-frontend.com", "https://my-other-frontend.com", "http://localhost:3000"],
credentials: true
}
});
このようにサーバー側のindex.jsの中でServerをインスタンス化する際の第2引数にクライアント側のURLすなわち、ポート番号を記述してやれば良い。
私達の場合、
const io = new Server(server, {
cors: {
origin: ["http://localhost:3000"],
},
});
このような記述になる。
ちょっと長くなるので続きはまた明日書く。