【Node.js】Socket.IO / Express / TypeScriptでリアルタイム通信を実現するソケットサーバー構築

こんにちは、[yamaday0u](https://yamaday0u.net/profile/)です。

今回はNode.jsの環境でチャットなどのリアルタイム通信を実現するソケットサーバーを構築する例をご紹介します。

かなりシンプルな構成で作りますので、これからNode.jsでソケットサーバーを作ってみたい多くの方の参考になると思います。
※2022年から技術系の記事は個人ブログにも投稿しております。個人ブログの記事は適宜修正しておりますのでぜひこちらもご覧ください→[yamaday0u Blog](https://yamaday0u.net/category/programmer/)

## プロジェクトの構成
プロジェクトの全容は以下のようになります。
```zsh
.
├── client
│   └── index.ts // クライアント側のプログラム
├── server
│   └── index.ts // サーバー側のプログラム
├── node_modules
├── package-lock.json
└── package.json
```
この記事の内容はソケットサーバー構築がメインですが、動作確認用にクライアント側も作成します。

ここで紹介するプロジェクトはぼくの[Github](https://github.com/yamaday0u/socket-practice)リポジトリに公開しています。良かったらご覧ください。（随時更新しているのでこの記事の内容とは変わっている可能性があります。）

### TypeScriptの採用理由

個人的に以前から触ってみたかったので、挑戦の意味も込めてTypeScriptでソケットサーバーを構築することにしました。

静的型付け言語ってかっこよくないですか？

## ライブラリのインストール
まずは必要なライブラリのインストールをします。

インストールするのは以下のライブラリです。

- typescript（typescriptでコードを書いていくため）
- express（サーバーとして機能させるため）
- socket.io（今回の主役ライブラリ）
- socket.io-client（クライアント用）
- ts-node（typescriptのままテスト実行するため）

ターミナルで以下のコマンドを実行します。
```zsh:ターミナル
npm install typescript express socket.io socket.io-client ts-node
```

```zsh:ターミナル
npm install -D @types/express @types/node
```

## ソケットサーバーの構築
いよいよサーバーを構築します。

[Socket.ioのドキュメント](https://socket.io/docs/v4/server-initialization/#with-express)に記載されている例を参考にして、expressをhttpを組み合わせて作ります。

```typescript:server/index.ts
import express from "express";
import { createServer } from "http";
import { Server } from "socket.io";

const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, { path: "/socket/" });

app.get("/", (req: express.Request, res: express.Response) => {
  res.json({
    message: "root path"
  });
});

io.on("connection", (socket) => {
  console.log("connected");
});

httpServer.listen(3000, () => {
  console.log("Chat server listening on port 3000");
});
```
サーバーを起動するためのコマンドのショートカット用スクリプトををpackege.jsonに追加します。

```json:package.json
{
  "name": "socket-practice",
  "version": "1.0.0",
  "description": "",
  "main": "server/index.ts",
  "scripts": {
    "server": "ts-node server/index.ts" // 追加
  }, (以下省略)
}
```
サーバーを起動してみましょう！

```zsh:ターミナル
npm run server
```
![スクリーンショット 2023-06-14 0.53.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849306/a14e7068-e509-fc15-a82c-619f2c80423d.png)
無事にサーバーが起動できました。

## クライアント側の構築
次はクライアント側を構築します。

```typescript:client/indexts
import { io } from "socket.io-client";

const socket = io("http://localhost:3000", { path: "/socket/" });

socket.on("connect", () => {
  console.log("client connected");
});
```
先ほどと同じようにクライアントを実行するコマンドのショートカットスクリプトをpackage.jsonに追加します。

```json:package.json
{
  "name": "socket-practice",
  "version": "1.0.0",
  "description": "",
  "main": "server/index.ts",
  "scripts": {
    "server": "ts-node server/index.ts",
    "client": "ts-node client/index.ts" // 追加
  }, (以下省略)
}
```

クライアントも起動してみましょう。

```zsh:ターミナル
npm run client
```

![スクリーンショット 2023-06-14 0.56.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849306/540f2652-0086-2a6b-9558-f21c31cce277.png)
clientがserverとつながりました。
先に起動させておいたサーバーもクライアントとつながって、”connected”のログが出力されました！

![スクリーンショット 2023-06-14 0.56.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849306/81389b14-eb60-cc1e-e41a-fcaef6575932.png)
server側でもclientとつながりました



## 参考資料
- [Socket.IO](https://socket.io/docs/v4/)
- [Socket.IO + Express + TypeScriptでリアルタイム通信を始めよう（たぬきうどんTechBlog）](https://bgtu-techblog.com/2022/11/25/socket-io-express-typescript%E3%81%A7%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%BF%E3%82%A4%E3%83%A0%E9%80%9A%E4%BF%A1%E3%82%92%E5%A7%8B%E3%82%81%E3%82%88%E3%81%86/)
- [Node.js | Socket.IOでリアルタイム双方向通信（わくわくBank）](https://www.wakuwakubank.com/posts/760-nodejs-socketio/)
- [【typescript】socket.ioでサーバー-クライアント間のやり取りを簡単に行う（Qiita）](https://qiita.com/NNNiNiNNN/items/53329d69fce9cb8e34af)