🌐

WebRTCでのP2P通信

2024/10/25に公開

https://zenn.dev/daddy_yukio/books/43790f0b74d317

WebRTC(Web Real-Time Communication)

WebRTC(Web Real-Time Communication)は、Webブラウザやモバイルアプリケーション間で、直接リアルタイムの音声、ビデオ、データ通信を可能にする技術で、SkypeやGoogle Meetのようなビデオ通話アプリケーションで広く使われています。

WebRTC自体はネットワークプロトコルではなく、異なるアプリケーション間でも共通のAPIや手順を用いてP2Pでのリアルタイム通信を実現する為のフレームワークです。

WebRTC APIに関しては、W3C(World Wide Web Consortium)によって標準仕様として策定されており、これによって異なるOS/ブラウザ間であっても互換性が確保されています。
また、WebRTCで使用する各所ネットワークプロトコルや関連する通信技術に関しては、IETF(Internet Engineering Task Force)によって標準化が行われています。
https://www.w3docs.com/learn-javascript/webrtc.html

こうしたWebRTCを構成する技術の中で、最も重要な機能の一つが、NAT(Network Address Translation)を越えて、P2P通信の経路を確立する技術です。

P2P(Peer to Peer)通信

ウェブブラウジングやメール、その他のクラウドサービスなど、現在のインターネットサービスのほとんどが、サーバ・クライアント型の通信方式で提供されています。


サーバ・クライアント通信

これに対し、P2P(Peer to Peer)通信とは、サーバーを介さずに、個々のコンピュータ同士が直接接続し、データの送受信を行う方式です。


P2P通信

WebRTC(Web Realtime Cominication)では、サーバを介さずにP2P通信を用いることで、低遅延で効率的な映像/音声の送受信を可能にしています。

ただし、サーバ・クライアント通信と比べて、P2P通信では、最初の接続の確立が難しい面があります。

その最も大きな要因がNAT(Network Address Translation)です。

NAT(Network Address Translation)

インターネット上で相手との通信を確立する為には、接続する相手の場所(=グローバルIP)が必要です。

グローバルIPとは、インターネット上で一意に識別されるIPアドレスのことを指します。インターネットに接続するデバイスが、他のネットワークやデバイスと通信するために、世界中でユニークなアドレスを持つ必要があります。このようなユニークなアドレスがグローバルIPアドレスです。

サーバ・クライアント通信の場合、接続先のサーバのグローバルIPアドレスは、多くの場合、ドメイン名という形で文字列として公開され、DNS(Domain Name System)サーバでグローバルIPに変換されます。

これに対し、一般家庭や社内LANなどでは、そのローカルネットワーク(LAN)内で自由に設定が可能なIPアドレス(プライベートIP)が使用されます。

このプライベートIPは、LAN内では自由に利用できますが、インターネット上では利用できません。

その為、ローカルネットワーク内で使用されるプライベートIPを、インターネット接続可能なグローバルIPに変換する技術が必要になります。

特に、IPv4では、グローバルIPアドレスの枯渇が懸念されており、1つのグローバルIPを複数のプライベートIPで共有して使用する為の技術として、NAT(Network Address Translation)が利用されています。

NATを介したインターネットとの通信手順

一般的な家庭では、インターネットに接続する為に、インターネットサービスプロバイダー(ISP)と契約して、グローバルIPを一つ、割り当てられます。この割り当てられたグローバルIPを使って、家庭内の複数のプライベートIPを設定した端末がNATを介してインターネットと通信することになります。

NATには様々な種類がありますが、ここでは最も単純なフルコーンNATの場合を例に、プライベートIPを設定したPCが、インターネット上のサーバと通信する流れを見ていきます。


家庭内のPCがルータのNAT機能を使って、サーバと通信する例

ルータには、家庭内のローカルネットワークと、外部のインターネットを接続する為に、2つのIPアドレスが設定されています。

一つは家庭内ネットワーク上のプライベートIPアドレス(192.168.1.1)、もう一つは、プロバイダーから割り振られたグローバルIPアドレス(12.34.56.78)です。

まず、家庭内のPCからサーバに対して通信を行う場合、ルータに対してその通信が送られます。


通信を受信したルータでは、PCからの通信を、インターネット上のサーバに転送します。その際、サーバ側からの返信をPCに通す為に、ポート番号(ここでは100番)を割り当てて、「グローバルIP側のポート100番への通信=192.168.1.5へ通す」というマッピングを作成します。


ルータから転送された通信を受信したサーバは、送信元のルータのポート番号100番に対して返信します。

このサーバからの返信を受信したルータは、「グローバルIP側のポート100番への通信=192.168.1.5へ通す」というマッピングが行われているので、192.168.1.5に通信を転送し、家庭内のPCがそれを受信する、という流れになります。

P2P通信とNAT

このように、NATのマッピングは、家庭内の端末からの通信をトリガーにして自動的に行われます。また、一度設定されたマッピング情報は、時間が経つと消えてしまう為、外部から家庭内のPCに直接通信しようとしても、NATのマッピングが存在していない状態では、外部からの通信はルータで遮断され、家庭内のセキュリティが保たれることになります。

しかし、WebRTCのようなP2P通信を行う場合は、このNAT機能が大きな壁となって、通信経路の確立を難しくしています。

WebRTCでは、このNATを越えるために、いくつかの手段を駆使して、P2P通信経路の確立を試みます。

WebRTCでのNAT越えの方法

WebRTCではP2P通信の接続を確立する為に2つの外部サーバを使用してNAT越えを試みます。

STUN(Session Traversal Utilities for NAT)サーバ

STUN(Session Traversal Utilities for NAT)は、NATを超えて、インターネット上でP2P通信を確立するために使われるプロトコルです。

NAT配下に存在する端末が、自分の通信がインターネットに出る際にマッピングされる、グローバルIPアドレスとポート番号を知るために使用されます。

下図は前章で説明したNAT配下のPCがインターネット上のサーバに接続する際の構成で、STUNサーバを利用した場合の概念図です。

NAT配下の端末からSTUNサーバに対してリクエストが投げられると、STUNサーバ側は、NATでマッピングされたグローバルIPとポート番号を返却します。

これによって、NAT配下の端末では、自分がインターネットからの通信を受信する際に使用されるNAT上でのマッピング情報(グローバルIPとポート番号)を知ることが可能になります。

こうして得た自分のグローバルIPとポート番号をP2P通信の相手に伝え、また、相手のグローバルIPとポート番号も教えてもらうことで、P2P通信が確立されます。

ちなみに、このSTUNは非常に軽量なプロトコルで、サーバの処理負荷も低いため、無償で公開しているサーバが数多くあります。

TURN(Traversal Using Relays around NAT)サーバ

TURN(Traversal Using Relays around NAT)は、NATやファイアウォールを越えてP2P通信の接続を確立する為に、通信の仲介を行うプロトコルです。

P2P通信はクライアント同士が直接データを送受信しますが、NATやファイアウォールの制限が厳しい場合、直接の接続ができないことがあります。このような場合に、TURNサーバーが中継サーバーとして機能し、クライアント間のデータ通信をサーバー経由で行います。

上図を見ると分かりますが、TURNサーバへの接続は、通常のインターネット上のサーバへの接続と同じなので、両方の端末が問題なく接続できます。そのうえで、それぞれの端末からの映像や音声をTURNサーバが中継役となって送受信を行う形です。

この形式は、サーバ・クライアント通信です。
当然、遅延が大きくなりますし、サーバの処理負荷が非常に高くなり、維持コストもかかることになります。

その為、WebRTCでは、まずは可能な限りSTUNによる直接P2P接続の確立を優先し、TURNはあくまでバックアップの手段として使用されるのが一般的です。

P2P接続までの流れ

STUNやTURNを利用して、P2P通信可能な最適なネットワーク経路を選択する為の仕組みを、ICE(Interactive Connectivity Establishment)と呼びます。

このICEを使用して、WebRTCでP2P通信を確立する手順を説明します。


ICEによるP2Pセッション確立までの流れ

1. ICE(Interactive Connectivity Establishment)候補の収集

まずは、自分が属するネットワーク経路の候補を、STUN/TURNを使用しながら収集します。
この経路情報には、主に次の3種類の候補が含まれます。

  1. 自身のプライベートIPアドレス(ローカルIPアドレス)
  2. STUNサーバを使って取得したグローバルIPアドレス
  3. TURNサーバを介した中継経路

2. 収集したICE候補情報の交換

収集したICE候補情報を、接続相手の端末と交換します。

ICE候補情報は、SDP(Session Description Protocol)の形式で記載され、交換されます。
SDPは、経路情報だけでなく、送信されるメディアの種類(ビデオ、音声、データなど)や、使用するコーデックなどの情報も記載されたテキスト情報です。

SDPの例
v=0
o=- 123456 654321 IN IP4 xxx.xxx.xxx.xxx
s=Example Session
c=IN IP4 xxx.xxx.xxx.xxx
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
m=video 51372 RTP/AVP 31
a=rtpmap:31 H261/90000

この情報交換(シグナリングと呼ばれます)のプロトコルに関しては、WebRTCとしては特に定義がなく、どのように実現するかはアプリケーションに任されています。
一般的にはWebSocket等を使用しますが、極端な話、メールでも構いません。(リアルタイム性が落ちますが。。。)

3. ICE接続確立

ICE候補情報を交換したら、それぞれの候補を使用して、STUNサーバを利用しながら、最も効率的で安定した経路を選定します。
直接接続ができない場合は、TURNサーバを介してリレー接続を行います。

4. セッションの確立

最適なICE候補が選ばれたら、実際にP2Pでのリアルタイムセッションが確立され、映像や音声が送信されます。

Vanilla ICEとTrickle ICE

収集したICE候補の交換方法には、2種類の方法が存在します。

Vanilla ICE

Vanilla ICEとは、ICE候補の収集が終了してから、SDPを交換する方法です。

すべてのICE候補の収集が終了するまで交換が行われないため、時間がかかることがありますが、その反面、すべての情報が一つのSDPに含まれている為、交換処理も1回ずつ行えばよく、処理としてはシンプルになります。

Trickle ICE

Trickle ICEとは、ICE候補を収集する際、収集できたICE候補情報を非同期で相手に渡す方法です。

Trickle ICEの場合、最初の交換では、メディア情報のみを記載したSDP情報を交換します。
その後、ICE候補が収集されるたびに相手に送信し、経路が確立できた時点で、P2Pセッションを開始する、というやり方です。

この方法だと、すべてのICE候補の収集が終了するまで待つ必要がなく、接続が確立できた時点でP2Pセッションを開始することが可能になり、接続までの時間を短縮できる可能性があります。

ただし、非同期で送信されてくるICE候補情報を受信して処理を行う必要がある為、Vanilla ICEと比較すると、実装は複雑になります。

Discussion