【JavaScript 応用講座】:[P2P通信入門] P2P通信でファイル送受信【簡易チャット付き】

はじめに

前回の記事で、simple-peerを使い、P2Pで接続を確立するまで出来ました。

本日は、その続きで、接続確立後のチャット、更に、ファイルの送受信処理を実装。

ChromeとFirefox間でP2P接続をして、チャットで簡易会話が出来るようになったほか、ファイルの送信と受信処理まで完成。

備忘録を兼ね、実装内容を記事にしてみました。

🛠 使用した技術

  • simple-peer
  • WebRTC
  • Blob / FileReader / ArrayBuffer
  • TextDecoder / JSON構造分離
  • IndexedDB(保存予定)

🔗 シグナリングと接続の流れ

P2P通信を成立させるには、まず最初に「signal情報(接続設定情報)」を手動で交換する必要があります。 この手順は将来的に「QRコード」や「シグナリングサーバー」によって自動化も検討しています。

今回は、以下のような手順で接続を確立させました:

  1. どちらかが「接続」ボタンを押して initiator: true 状態になる
  2. 画面に表示された signal 情報(SDP + ICE candidate)をコピーして、もう一方に貼り付ける
  3. 双方が signal 情報を送受信することで、接続が確立!

接続に成功すると、✅ P2P 接続が確立しました! と表示されます。


💬 チャット機能の実装

まずはテキストチャット機能から作成。 これは JSON オブジェクトを送信する形で、下記のように定義しました。

const message = {
  type: "chat",
  text: "こんにちは!"
};
peer.send(JSON.stringify(message));

受信側では TextDecoder で文字列に復元してから JSON.parse() して処理します。

peer.on("data", (data) => {
  const text = new TextDecoder("utf-8").decode(data);
  const obj = JSON.parse(text);
  if (obj.type === "chat") {
    appendLog("🔵 相手: " + obj.text);
  }
});

📦 ZIPファイルの送受信

ここが今回の最大のチャレンジです!

ZIPファイルは一度に送るにはサイズが大きいため、以下のような 分割送信+再構成方式 を採用しました:

🚀 送信側の流れ

  1. file-begin イベントでファイル名を通知
  2. ファイルを Uint8Array に変換
  3. 64KBずつ分割して送信(DataChannelの安全範囲内)
  4. 最後に file-end イベントを送信
peer.send(JSON.stringify({ type: "file-begin", name: file.name }));
while (offset < total) {
  peer.send(fileData.slice(offset, offset + chunkSize));
  offset += chunkSize;
}
peer.send(JSON.stringify({ type: "file-end" }));

📥 受信側の流れ

  1. file-begin を受け取ったら受信開始
  2. バイナリ(Uint8Array)としてチャンクを保存
  3. file-end を受け取ったら Blob に復元 → ダウンロード!
if (obj.type === "file-begin") {
  receiveChunks = [];
  currentFilename = obj.name;
} else if (obj.type === "file-end") {
  const blob = new Blob(receiveChunks);
  const url = URL.createObjectURL(blob);
  // ダウンロード処理へ
}

🧪 実際の画面と進捗ログ

以下は、送信中の画面ログです。 進捗ログも「送信中: N / 全体サイズ」形式でリアルタイムに表示されます。

今後の課題

  • 進捗バーの今後の実装構想(progress bar)
  • IndexedDB連携
  • 手動ではなく自動で接続

現在は、動作テストでsignal情報を手動で貼り付けて接続していますが、シグナリングサーバーを作成して自動で作成する仕組みの実装を明日以降やっていくことになると思います。

チャットUIは即席で作成した物なので、実際は大幅にデザイン変更になると思います。

これだけ毎日やってると流石にHTML/CSSにも慣れてきましたが、それでもUIを作るのが地味に大変です…。