
WebRTCのNAT越えに失敗した
閉域でWebRTCを使う
以前の記事で少し話題にしたのですが、閉域でWebRTCを開発しています。しかし、ネットワーク構成的に、シグナリングあれば行けるっしょとタカを括っていたのですが。。。
シグナリングはうまくいっているのに動画もデータ通信も始まらない!
…どういうことだってばよ? シグナリングサーバのログで、Webソケット通信が試みられた場合にログを出力しており、ここは問題なし。OfferがAnswerのSDPやICEを受け取ったのも確認。
なにか大切なことを忘れている気がする(´・_・`)
このOfferとAnswerとしているPeerたちは、AnswerからOfferへはプライベートIPで通信できるが、逆はOfferからAnswerの間にいるルーターがNAT機能を持っているため、送信と受信の経路が異なります。一方は直接通信できるが、逆方向はNATの影響で通信できないネットワークになっています(これを非対称ルーティングという)。
片側が通信できるからとタカを括っていたツケを払わされる。
ここで、
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
console.log("Generated ICE Candidate (Offer):", event.candidate);
} else {
console.log("All ICE candidates sent (Offer).");
}
};
このようにICE Candidateを監視しておくと、ICEの詳細なデータをevent.candidate上で見ることが可能です。 それを確認すると
{
...
typ: host
...
}
という記述があります。typがhostとなっている際は、ローカルネットワーク内で直接通信できることを表します。しかし、NATの影響がある非対称ルーティングの場合は考慮することができません。
※お恥ずかしながら、NAT機能は、インターネットとプライベートネットワークの変換のことを指すと思っていましたが、今回のようにインターネットを介さない場合の異なるセグメントを中継する際にもNATが使われるらしいです(´・_・`)。
閉域ネットワークだから!(NATを越えないとは言っていない)
まさしくこのようなネットワークだったというワケです。このような場合、STUNサーバを用意して、NATの変換前/変換後の情報を組み合わせて、NATを越えてあげる必要があるわけです。
ですが、閉域ネットワークなので、天下のGoogleがホスティングしているサーバは使用できません。そのため、COTURNなどを使用して、閉域にSTUNサーバを設置する必要があるかなと考えています。 また、STUNはシグナリングのようにWebソケットサーバを自前で用意する必要がなさそうです。以下のように、Peerインスタンスを作成する際に、iceServersを追加し、サーバー名とポートを指定するだけで良さそうなので、書くだけなら楽チンそうです(´・_・`)。
const peerConnection = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
}); //↑を自前で用意したCOTURNサーバのIPにする
ちなみにSTUNサーバを使用すると、ICE Candidateのtypが変わり、
{
...
typ: srflx
...
}
というタイプになるらしいです。さらに 外側から見えているIPに加えて、raddrという項目に変換前のプライベートIPも含まれます。これを確認すれば、STUN が正しく動作しているか分かるはずです。STUNによるNAT越えがうまくいっているかは、引き続きICE Candidateを確認すれば良さそうですね。戦いは続きます(´・_・`)。