Home


Community


Resources

File Center
Links




Since April 10th, 2000



View Developers' Corner Pages INVITE OTHERS | HELP | FEEDBACK
GUEST LOG IN | JOIN GROUP  
  Back to all pages
開発者のコーナー
Index | Scaling GnutellaNet | Windows GUID and PUSH | Protocol | The Daily Spam

開発: プロトコル

Gnutellaプロトコル

Last update: 15 April 2000

PUSHリクエストの経路選択の説明書を更新した。コメントはgene@wego.comへどうぞ!

またプロトコルの仕様についてはACEさんのページでわかりやすい説明がご覧になれます。
貴重なフィードバックを戴いたWolfyさん、ACEさんに感謝致します。


覚書き
すべてはネットワークバイトオーダーである。GUIDのバイトオーダーは重要ではない。

明らかに、"\r" と "\n"が何なのかについていくらか混乱が存在する。 さて \r はキャリッジリターン、あるいは 0x0d であり、\n は改行あるいは 0x0a である。"man ascii"によればこれは標準ASCIIである。

君が送ったメッセージは複数のホストによって応答があるということを覚えておいてほしい。だから、Pong(Pingへの応答)がホストの情報を含んでいるのでPingはホストを発見するために使われている。

この文書の中では、サーバとクライアントという語句は表裏一体です。Gnutellaのクライアントは同時にサーバでもあります。

苦労してプロトコルをデコードして報告してくれたcapnbryに感謝します。

GnutellaNetの動作メカニズム

一般的な説明

GnutellaNetは"ウィルスの増殖"のように動作する。私があなたにメッセージを送るとあなたはそのメッセージを接続している全てのクライアントに送る。そんなわけで、残りのネットワーク全てを知るためには私はあなただけ知っていればよい。

このメッセージ配送の仕組みを一見するとあなたはそれが無秩序な程の量のトラフィックを発生するのではないかと思うだろう。Gnutella 0.54のデフォルトを例にとってみよう。GnutellaはデフォルトであるTTL(TTLはTime to Live あるいは、あるメッセージが死ぬまでに通過することのできる回数を意味する。)値をもった25のアクティブな接続を維持しようとする。最悪の場合、これはたった1つのメッセージが257あるいは、6103515625(60億)のメッセージを発生させることを意味する。

さて、実際はそれほど最悪なことは起きない。現実にはいつでも2000より少ないクライアントしかGnutellaNetに存在しない。それは我々の仮想上のメッセージにおけるTTL値が失効するずっと前に、すべてのクライアントが我々のメッセージを既に見たことになるからだ。

明らかにいったんクライアントがあるメッセージを見てしまえば、もうそのメッセージを処理する必要がない。本来のGnutellaの設計者たちはこのことを認識しており、Gnutellaがネットワーク上でそれぞれのメッセージを一意に識別できるようにそれぞれのメッセージにGUID(Globally Unique Identifier)を含めるように設計した。

じゃぁ、GnutellaクライアントがGUIDをもっているとどんないいことがあるんだろう?各Gnutellaクライアントは一度見たGUIDの短期記憶を保持している。たとえば、 私は自分が受け取ったメッセージは覚えているだろう。 もし私がまだ見ていないメッセージであれば、私はそのメッセージを適切であるとしフォワードする。もし私がそのメッセージを見たことがあれば、それは私がすでにそのメッセージをフォワードしているということになり、私がフォワードしたものはすべて見たことがあるメッセージということになる。だから私は増殖を気にせずに済むしみんなを心配事に巻き込まずに済む。

トポロジー

GnutellaNetには階層構造がない。全てのサーバは平等である。すべてのサーバはまたクライアントでもある。 だからどんな人も貢献できる。すべての平等主義的なシステムのように他のシステムより平等なサーバがある。高速な接続で走っているサーバはより多くのトラフィックをサポートする。それらは他のシステムへのハブになり、より素早くリクエストに応える。低速な接続のサーバはGnutellaNetの僻地へ降格されより遅く検索結果を受け取る。そしてもしそれが高速な環境の振りをすれば、パケットの洪水を浴びて死ぬことになる。

しかし、それは階層構造がないということだけで、もたらされたのではない

それぞれのGnutellaサーバは直接自分に接続しているサーバについてのみを知っている。PINGに応答するかQUERYに応答することで自身を報告しなければ、その他のサーバは見えない。これは驚くべき匿名性をもたらす。

不幸なことに、階層構造が存在しないこととサーバリストを発見する材料がないことの組み合わせはネットワークを説明づらくしている。それは木構造ではなく(階層構造がなく)円環的な構造なのだ。円環的なネットワークは多くの不必要なネットワークトラフィックが存在することを意味する。今日のクライアントはトラフィックを緩和する十分な機能がない、しかしスケーラブルなGnutellaNetのためには開発者がこの問題を考え始めることが必要になるだろう。

サーバに接続する場合
最初にサーバへの接続を確立したあと、握手(handshake)をしなければならない。今のところ握手はとてもシンプルだ。接続しようとしているクライアントは次のように言う:

GNUTELLA CONNECT/0.4\n\n

それを受け入れるサーバは次のように返事をする:

GNUTELLA OK\n\n

それが全てだ。

サーバからダウンロードする場合
サーバからファイルをダウンロードするのはとても簡単だ。それはHTTPで行われる。ダウンロードしようとしているクライアントは普通のやりかたでファイルを要求する:

GET /get/1234/strawberry-rhubarb-pies.rcp HTTP/1.0\r\n
Connection: Keep-Alive\r\n
Range: bytes=0-\r\n
\r\n

みてきたようにGnutellaは部分的なファイルのダウンロードを再開するためのパラメータをサポートしている。1234はファイルインデックス(下にあるHITSセクションを見よう)で、"strawberry-rhubarb-pies.rcp"がファイル名だ。

サーバは普通のHTTPヘッダで返事するだろう。たとえば:

HTTP 200 OK\r\n
Server: Gnutella\r\n
Content-type:application/binary\r\n
Content-length: 948\r\n
\r\n

重要な部分は"Content-Length"ヘッダだ。これはどのくらいのデータ量かを教えてくれる。全部受け取ったらそのソケットを閉じる。

ヘッダ
bytes 概要 説明
0-15 メッセージ識別子 これはWindowsのGUIDだ。私はこれがどのようにglobally-uniqueであるべきなのか本当に理解しているわけではない。それは特定のメッセージを既に見たものかどうか判断するのに使われている。
16 ペイロード識別子(function identifier)
機能
0x00 Ping
0x01 Pong (Pingへの応答)
0x40 Push request
0x80 Query
0x81 Query hits (Queryへの応答)
17 TTL Time to live. TTL値はフォワードされる度に1づつ減算される。もし1より小さいTTLをもつ受け取ったメッセージは、フォワードされるべきではない。
18 Hops このメッセージがフォワードされた回数。
19-22 ペイロード長 続くペイロードの長さ。

Payload: ping (function 0x00)
ペイロードなし
経路選択の説明
PINGパケットを接続しているすべてのクライアントにフォワードしなさい。他のほとんどのドキュメントにはその発信元にパケットをフォワードすべきではないと述べられている。私はそれはとてもよい最適化であると思うが、本当に必要なことではない。サーバはパケットの発信元にパケットを送らずに済むほど十分に賢くなくてはならない。

GnutellaNetのトラフィックを大まかに分析するとネットワークトラフィックの約50%がPINGであることがわかる。明らかにこれは最適化される必要がある。今日のクライアントの問題の一つは定期的にネットワークにPINGしていると思われることだ。実際これは必要なことだが、更新のためのPINGの頻度は劇的に減らしうる。単純にあなたのクライアントが経路を指定したPONGメッセージを注意深く見ることによってたくさんのホストを捕まえることができる。

PINGの数を本当に減らしうる方法は、PONGデータを含むようなPINGメッセージをサポートするようにプロトコルを変更することだ。そうすることで、ホストを探すのではなく、ホストが自らを知らせてくれるのを待つだけで済むようになる。

Payload: pong (query reply) (function 0x01)
bytes 概要 説明
0-1 ポート番号 IPv4でのポート番号
2-5 IPアドレス IPv4でのIPアドレス。x86のバイトオーダーでリトルエンディアンです!
6-9 ファイル数 そのホストが共有しているファイルの数。
10-13 キロバイト数 そのホストが共有しているキロバイト数。
経路選択の説明
すべての応答と同じように、PONGパケットは経路選択される。つまり、PINGが来た経路とは逆の方向にこのパケットをフォワードしなければならない。もしあなたがそのPINGを見なかったら、そのとき決して起きてはならない奇妙な状況に陥ることになる。なぜって?もしあなたがこのPONGに相当するPINGを見なかったら、そのサーバがこのPONGを間違った経路に送っていることになるからだ。

Payload: query (function 0x80)
bytes 概要 説明
0-1 最低速度 この要求に応答するべきサーバの最低速度(キロビット/秒)
2+ 検索基準 検索キーワード、あるいは他の判断基準。NULLで終了。
経路選択の説明
接続しているすべてのサーバにQUERYメッセージをフォワードする。

Payload: query hits (query reply) (function 0x81)
bytes 概要 説明
0 ヒット件数 (N) この設定でのヒット件数。後述する"検索結果の集合"を参照。
1-2 ポート番号 IPv4でのポート番号。
3-6 IPアドレス IPv4 でのIPアドレス。x86 のバイトオーダーはリトルエンディアンです!
7-10 速度 応答中のホストの速度(キロビット/秒)
11+ 検索結果の集合 これらの属性がN個ある (上述の"ヒット件数" を参照).

bytes 概要 説明
0-3 インデックス ファイルのインデックス番号
4-7 サイズ バイト単位のファイルサイズ
8+ ファイル名 ファイルの名前。終端は二重のNULL。

Last 16 bytes クライアント識別子 応答中のホストのGUID。PUSHで使われる。
経路選択の説明
HITS(ヒット情報)は経路選択される。これらのメッセージは発信元からの経路を遡って送りなさい。

Payload: push request (function 0x40)
bytes 概要 説明
0-15 クライアント識別子 プッシュすべきホストのGUID
16-19 インデックス ファイルのインデックス番号(クエリーヒットで与えられたもの)
20-23 IPアドレス IPv4でのプッシュ先アドレス
24-25 ポート IPv4でのプッシュ先のポート番号
経路選択の説明
クエリーヒットが配送された経路を辿ってのみPUSHメッセージをフォワードしなさい。クエリーヒットを見失った場合、PUSHリクエストの配送において役に立たないので、パケットは失われる。

PUSHリクエストに対するPUSH処理(GIVメッセージ)について
Wolfyさん(Jnutella MLより)
---
Aをダウンロードする方、
Bをアップロードする方とします。

1.AはBの持つファイルをダウンロードしようとするがBに接続できない場合
gnutellaNetにPushを送ります。Pushには、Aのアドレス、ポート、BのGUID、
ダウンロードしたいファイルのインデックスを書いています。

2.Bが運良くPushを受け取って自分のGUIDと一致すれば、
BはAのアドレスのポートに直接接続してGIVを送ります。
GIVのフォーマットは、
GIV 1234:00112233445566778899AABBCCDDEEFF/abcd.mpg[LF][LF]
1234がファイルインデックス、
00112233〜がGUIDの16バイトを16進の文字列にした32文字、
abcd.mpgがファイル名、
最後に LF(0x0a)を二つです。

3.Aの欲しいファイルがGIVのファイルと一致すれば、その接続をそのまま使って、
GETリクエストを送ります。後は通常のダウンロードと同じです。
---

これについてはフィードバックが必要です。






Wego.com, Inc., does not claim ownership of or take responsibility for any content on this site.
There is no warranty or guarantee on anything downloaded from this site.
Gnutella Website Support