この通信は何のためにあるのか
ロビーに入ったあと、部屋を作る・部屋を探すという操作を受け持つのがcivgs-gamebrowserである。タイトルにあるQRとSBは、ここで使われる、向きの違う2つの通信の略称である。どちらもGameSpyが提供していた仕組みの名前で、ロビー画面の部屋一覧はこの2つで成り立っている。
- QRは、Query & Reporting(クエリ・アンド・レポーティング)の略である。部屋を作った側(ホスト)のクライアントが、「こんな部屋を作りました」「この部屋はまだ開いています」と、自分の部屋の状態をサーバーに報告するための仕組みである。
- SBは、Server Browser(サーバーブラウザ)の略である。部屋を探す側(参加者)のクライアントが、サーバーから部屋の一覧を取得するための仕組みである。「サーバー」はゲームの部屋のことを指しており、その一覧を眺める機能、という意味の名前である。
| 略称 | ポート | 役割 |
|---|---|---|
| QR | UDP 27900 | 部屋の登録と生存報告 |
| SB | TCP 28910 | 部屋一覧の取得と増減の通知 |
ホストが部屋を作ると、クライアントはcivgs-gamebrowserのQRに、部屋の情報を報告する。サーバーはこれを部屋の台帳として持ち、参加者がSBで一覧を要求したときに返す。ホストは部屋が開いている間、定期的に報告を続ける。部屋が増えたり減ったりしたときは、一覧を開いている参加者にも通知される。ホストからの連絡がしばらく途絶えた部屋は、台帳から自動的に削除される。
なぜ普通のサーバーでは動かないのか
QRもSBも、GameSpy独自の形式で作られた通信である。特にSBの応答は扱いが厳しく、それらしいデータを返せばよいというものではない。
- 一覧の応答は保護されている。 応答は暗号化されており、クライアントが期待する決まった手順どおりに組み立てないと、読むことができない。
- 応答の中身は、クライアントが「そう書いてある」と信じて読む。 各部屋のデータには、続く内容の構成を示す情報が付く。実際のデータと食い違うと、クライアントは以降を取り違えたまま読み進める。実際にこの食い違いを起こすと、Civ4クライアントがクラッシュすることを確認している。
このため、civgs-gamebrowserはこの形式に合わせて作られたものを使う必要がある。Civ4 Internet Lobbyでは、pylobbyのゲームブラウザ実装をベースにしている。
参加方式を決める通信である
IRCの通信(TCP 6667)とは違い、この通信は**「部屋に参加できるかどうか」に直接関わる**。サーバーは一覧を返すとき、参加者に対して「サーバーから見たあなたの接続元アドレス(公開IPアドレス。インターネットから見える、自宅の回線のアドレス)はこれです」という情報も伝える。参加者側のクライアントは、これを一覧の中のホストの公開IPアドレス(部屋を登録してきた接続元)と比べ、次のように接続方式を決める。
つまり、サーバーから見た「ホストの接続元IP」と「参加者の接続元IP」が一致するかどうかで、参加の経路が変わる。ロビーサーバーをインターネット側(WAN)に置いているのは、この判定が意図どおりに働くようにするためでもある。ホストと参加者が同じ家庭内ネットワークにいれば、どちらも同じグローバルIPアドレスとして見えるので、LAN内で直接つながる。別々の場所にいれば、NAT越えの仕組み(家庭のルーターの内側にいる者どうしが、ポート開放をしなくても直接つながるための手順)によってつながる。NAT越えの流れはシステム全体像と通信シーケンスを参照してほしい。
この判定は、同じサーバー、同じパケットキャプチャの中で、両者の接続元IPが揃った瞬間に失敗から成功に変わる実験によって確かめている。
ホストが申告する情報は原因ではない
ホストのクライアントは、部屋をサーバーに登録するとき(QRの報告)、大きく2種類の情報を送る。
- 部屋の表示用の情報: 部屋名、マップ、人数など。ロビーの部屋一覧に表示される内容で、参加者にも届く。
- ホスト自身のネットワークに関する情報: 「自分の公開IPアドレスとポート番号はこれ」「NAT越えが必要か」といった項目。ホストのクライアントが自分で判断して書き込むもので、これをホストの自己申告値と呼んでいる。
サーバーは、自己申告値が正しいかどうかを確かめず、そのまま台帳に載せている。実際に、ホストが申告した公開IPアドレスは、回線の本当の公開IPアドレスと食い違っていた。ルーターの内側にいるホストのクライアントは、自分の公開アドレスを正確には知らないためと考えられる。
このため、当初は「ホストの自己申告値が間違っているせいで、参加できないのではないか」と疑っていた。しかし、参加者が一覧を要求するときに指定する項目に、自己申告値は含まれていない。つまり、自己申告値は参加者には届かず、参加できるかどうかにも影響しないことが確認できている。参加可否の判定に使われるのは、サーバー自身が観測した接続元アドレス(前の節の図の判定)である。参加できない原因を探すときは、自己申告値は切り分けから外してよい。
症状から見る切り分け
部屋が見えない、参加できないときに、プレイする側が試せることをまとめる。ロビーサーバーの中は見えないので、次の順に「自分の側で正しいか」を確かめていく。
- hostsファイルが参加方法のとおりになっているか。 一部だけ追記した場合に抜けが出やすいので、内容を丸ごと貼り直すと確実である。書き換えたあとは、Civ4を再起動する。
- 稼働状況・お知らせで、ゲームブラウザの行が「● 稼働中」か。 「● 稼働中」なら、この記事のQR・SB・NAT越えを処理するサーバー側の準備はできている(この3つは同じプロセスである)。「● 停止中」なら、サーバー側の問題なので復旧を待つ。
- 参加する全員のCiv4が、同じバージョン(3.19)か。 バージョンが違うと、接続できない。
- パソコンのウイルス対策ソフトやファイアウォールが、通信を遮断していないか。
そのうえで、症状ごとの目安は次のとおりである。
- 自分が作った部屋が、他の人の一覧に出ない: 上の1〜4を、部屋を作ったホストのパソコンで確認する。確認したあとで、部屋を作り直してみる。相手側のhostsが原因のこともあるので、相手にも1を確認してもらう。
- 部屋の一覧が空のまま、または一覧を取得できない: 上の1と2を確認する。
- ロビーの処理が、途中で次々に失敗する: hostsファイルに、お使いのエディション名の付いた名前が、まとめて登録されていない可能性が高い。1のとおり、内容を丸ごと貼り直す。
- 一覧には部屋が出るが、参加操作で「交信しています」のまま固まる: hostsファイルに、お使いのエディション名の付いた、NAT越え用の名前が登録されていない可能性が高い。1のとおり、内容を丸ごと貼り直す。
それでも直らないときは、掲示板に報告してほしい。次の内容を書いてもらえると、原因を絞りやすい。
- お使いのエディション(BTS日本語版など)と、OS(Windows、Linuxなど)
- 部屋を作る側(ホスト)か、参加する側か
- どの操作で、画面にどう表示されたか
ログインの側の仕組みについては、ログイン時のGameSpy Presence(GP)通信(TCP 29900・29901)についてを参照してほしい。