[YukiWiki] [[read.cgiの仕様2]]

[ トップ | 一覧 | 編集 | 差分 | 単語検索 | 最終更新 | ]

[[read.cgiの仕様2]]とは何か

最新版ソースコード http://star.endless.ne.jp/users/forcount/contents/scriptmaker/read11.rev1.c

P2Pcache

 /******************************************************************************
  *                                                                            *
  *    2chのような掲示板システムってP2Pで                                      *
  *                                                                            *
  *        Version:01.00  Date:2000/08/26  修正者:デフォルトの名無しさん    *
  ******************************************************************************/

 /*============================================================================*
    企画段階
  *============================================================================*/

 ■NNTPの利用

 ・掲示版の良い点のリアルタイム制を保てない
 ・削除コントロールが簡単に偽装できてしまう
 ・多少スペックが必要

 ■キャッシュサーバ

 ・個人のスペックではきつい
 ・細かいキャッシングで上手く威力を発揮するか不透明

 ■結論

 個人単位で参加出来るようなキャッシングの仕組みをつくるのが良い。

 /*============================================================================*
    P2Pの概要
  *============================================================================*/

     -------------------------------------------------------
     |       www.2ch.net (P2P Master)      |
     -------------------------------------------------------
       ↑   |              ↑※3マスタ要求取得
   HTTP   |   |HTTP(一覧(board, thread,  |※4キャッシュサーバ登録
 (GET/POST) |   ↓  cache_ip_port)を入手)  ↓
     -------------------------------------------------------
     |          P2Pcache            |
     -------------------------------------------------------
   ※1  ↑   |              ↑
   HTTP   |   |HTTP            |※2独自の
 (GET/POST) |   ↓              ↓キャッシュやり取り
      ----------------         ----------------
      | ブラウザ |         | P2Pcache |
      ----------------         ----------------

 ※1:通常のHTTP要求時はHTTP Proxyもしくは
    2ch専用のHTTP Daemonとして、P2Pcacheは動作する。
    2chの場合にはCGIなどからHTTPにて一覧を入手し、
    キャッシュ内容をブラウザに伝える。
    キャッシュ単位はスレ単位、レス単位である。
    また、この時に新規スレの追加などの情報も取得する(If-Modified-since?)。
    鯖側はピアグループを決定し、一覧を送る。
    2chへの書きこみはデータの統一/即時反映のため、
    P2Pcacheは単に素通りさせ鯖に直接行う。
 ※2:P2Pcacheは、自分がキャッシュを持たない部分については、
    2chから送られてきた一覧を用い、他のキャッシュに検索にいく。
 ※3:一定時間内に発見できなかった場合には、マスタ(2ch)を入手し、
    自分のところにキャッシュし、ブラウザに伝える。
    但し、2ch内で常時P2P Masterを立ち上げるのは良くない?ので
    HTTPでやりとり?
 ※4:P2Pcacheは初めて自分が使用された際にマスタに登録する。
    有効時間を過ぎると、マスタは自動的に登録を抹消する。

 /*============================================================================*
    2ch側全般
  *============================================================================*/

 /*----------------------------------------------------------------------------*
     2chへのアクセスイメージ
  *----------------------------------------------------------------------------*/

 ●index2.html にアクセスする時 
 ttp://www.2ch.net/board/p2p.cgi?do=floterlist にアクセス。 
 スレ番号の一覧が帰ってくる。 
 その一覧を元に各スレにアクセスする。 

 ●特定スレにアクセスする時 
 ttp://www.2ch.net/board/p2p.cgi?do=reslist&thread=XXXXXX&from=XX&to=XX にアクセス。 
 レスのハッシュとサイズのペアの一覧が帰ってくる。 
 一覧を元に検索クエリーを投げ、レスのデータを集める。 
 その時にはもちろんサイズとハッシュを照合する。 

 484 名前:375 投稿日:2001/08/26(日) 03:00
 あと &ls=100 っていうリクエストについてはどうしましょう。 
 強制的に &st=XX&to=XX に置き換えさせないと示すレスの範囲が 
 変わってしまいますよね. 

 485 名前:266 投稿日:2001/08/26(日) 03:02
 >>484 
 それは p2p.cgi に ls オプションの処理をつければいいと思います。 
 p2p.cgi は今の read.cgi とほぼ同様の機能を持っているけれど 
 出力されるデータはスレ番号やレス要約の一覧ばかりである、 
 というような格好が適当じゃないでしょうか? 

 /*----------------------------------------------------------------------------*
     2ch側機能関連
  *----------------------------------------------------------------------------*/

 ●ピア管理
 ピア管理は 2ch.net 上で行う。 
 read.cgi に細工をほどこし、2ch.net にアクセスしてきたユーザーで 
 USER_AGENT が P2Pcache のそれになっているユーザーのIPを 
 アクセスされた板の住人としてピア一覧に登録する。 
 この登録は時限設定するものとし、 
 例えば最後のアクセスから一時間放置されたら除外する。 
 ピア一覧には CGI 経由でアクセスすることができる。 

 ●レスとスレの一覧管理
 read.cgi に細工をすることでスレへの書き込みと同時に 
 書き込み内容のハッシュのリストを生成これを 2ch.net 上に保存する。 
 また、フローティングスレッドやスレ一覧などのデータも保存する。 
 P2Pcache はまずこれらのリストを 2ch.net 上から取得し、 
 このリストに含まれるレスをピアや 2ch.net 上から収集する。 

 ●データ改竄対策
 2ch.net 上にあるレス情報にサイズやハッシュなどを含め 
 ピアから収集したレスとの照合を行うことである程度防げる。 
 照合に失敗した場合には 2ch.net から直接レスを取得する。 
 仮にハッシュがたまたま誤って一致してしまった場合でも 
 架空のレスが他のレスに入れ替わる程度で済み実害はほとんどない。 
 ※2chのマスタ、他のP2PcacheからもらったデータのMD5などと比較する。

 MD5 C言語
 http://www.rfc-editor.org/cgi-bin/rfcdoctype.pl?loc=RFC&letsgo=1321&type=ftp 

 MD5 Perl
 http://search.cpan.org/search?mode=module&query=MD5 

 561 名前:デフォルトの名無しさん 投稿日:01/08/26 17:03
 >>553 
 perlのMD5チェックしてみました。 
 大抵は入っていると思いますが、入ってなければ、 
 http://www.cpan.org/modules/by-module/Digest/Digest-Perl-MD5-1.5.tar.gz 
 解凍して、MD5.pm突っこんで、@INC設定されてなければ 
 指定すればOKそうです。 

 ex) 
 ./Digest-Perl-MD5-1.5/lib/Digest/Perl/MD5.pmにおいた時。 
 --- 
 #!/usr/bin/perl -w -I./Digest-Perl-MD5-1.5/lib 
 use Digest::Perl::MD5 'md5_hex'; 
 print 'Digest is ', md5_hex 'foobarbaz', "\n"; 
 --- 

 /*----------------------------------------------------------------------------*
     2ch側実装関連
  *----------------------------------------------------------------------------*/

 ●2ch.net 側の実装物について 
 ピア管理を行う CGI の実装が必要。 
 次のような動作をするものでよい? 

 基本的な動作は 2ch.net 上の各種のリストを読み出すこと。 
 動作パラメータは次の通り。 

   do:読み出し対象リストの選択。値は以下のいずれか。 
     threadlist = スレ番号の一覧 
     reslist = レス情報の一覧 
     abornlist = あぼーんされたレスの番号の一覧。 
   board, thread:板やスレッドの指定。 
   from, to, ls, nofirst:read.cgi に同じ。読み出し範囲の指定。 
   bycontent:do==reslist && bycontent==true ならばレスの文面を返す。 

 レス情報は、レスIDとレスサイズ、ハッシュのペアからなる。 
 レスIDは時系列にそって順序比較が可能で各レスについて固有であれば何でもよい。 
 reslist bycontent はキャッシュヒットしなかった場合の差分更新に用いる。 

 ●文字コードとレスID
 571 名前:デフォルトの名無しさん 投稿日:01/08/26 18:22
 >>568 
 :問題は string の文字コードをどうするかということと 
 既存の2chのdatがSJISなのでSJIS統一が移行が楽なんでわ。 

 :resID_t の中身をどうするかといったところです。 
 search->found->retrieve->responseが一つのセッションで 
 行われるなら、searchにて、boardとthreadが指定され範囲が 
 スレ内の一意性に帰着するから、datの頭からの行数をresID_t 
 にして、番号ずれが起きないように、削除時には\nは消さないで 
 削除マークを付けるのは如何? 
 行数==resID_tなら採番はしなくて済む。 
 また、書込は2ch.net一ヶ所で受けるから矛盾はでないはず。 
 ただし、searchからが一連のセッションでないなら、 
 retrieve, responseにも、board, threadを指定しないと、 
 resID_tだけで一意に特定するのは困難だと思う。 

 ちなみに、他すれでindexつけたいね、という話がありましたから 
 board, threadは、stringでなく、一覧で数値管理の方が、 
 はやいしトラフィックも少しだけ減るかも。 

 575 名前:266 投稿日:01/08/26 18:39 ID:V6I8TU7U
 >>571 
 素直にレス番号を使うということですね。それでやってみます。 
 search から response までは一つのセッションにまとめられます。 
 board, thread の番号も long あたりで表現できるなら楽でいいです。 
 ところで今のスレ番号って time か何かの値ですよね? 
 そうなら板名と long 値のペアで当面は表現できます。 

 /*============================================================================*
    P2Pcache側全般
  *============================================================================*/

 /*----------------------------------------------------------------------------*
     P2Pcacheの実装関連
  *----------------------------------------------------------------------------*/

 ●P2Pcache間の通信仕様について
 P2Pプロトコルに基づいて動作するサーバント兼 
 その動作過程で獲得したデータを整形してブラウザに送る 
 HTTPd としての実装が必要。 
 以下ではプロトコルについて述べる。 
 ※「2ch側実装関連」−「文字コードとレスID」なども参照のこと。

 プロトコルはメッセンジャーの非同期な交換としてモデル化する。 
 すなわち、ピアは他のピアへとメッセンジャーを送信するが、 
 どのメッセンジャーも独立しており、返信を必須条件としない。 
 ある目的に沿って二者間でメッセンジャーが継続的に往復する時 
 この往復の全体をセッションと呼ぶものとする。 

 メッセンジャーは次のフォーマットをとる。 

 struct Messenger{ 
    struct Header ; 
    struct Message ; 
 } ; 

 struct Header{ 
    time_t timeStamp ; 
    GUID inquirerID ; 
    GUID answererID ; 
 } ; 

 Message の中身はメッセージの種類ごとに異なる(後述)。 
 Header の各フィールドは次の意味を持つ。 

   timeStamp:メッセンジャーが生成された日時。 
   inquirerID:メッセンジャーの生成者を識別する一意なID。 
   answererID:メッセンジャーへの応答者を識別する一意なID。 

 inquirerIDとanswererIDはセッションごとに生成される。 

 ピアAが search メッセージを持つメッセンジャーを生成する。 
 この時にメッセンジャーの inquirerID を初期化する。 
    ↓ 
 ピアAは生成したメッセンジャーを直近のピアにばらまく。 
    ↓ 
 メッセンジャーを受け取ったピアはそのメッセージをチェックし、 
 自分の抱えるキャッシュ内を検索してレスの有無を調べる。 
 レスが見つからなければ受信したメッセンジャーを複製して 
 更に自分の直近のピアにばらまく(無限拡散防止などはgnutellaとほぼ同じ)。 
 この時、「メッセンジャーをどのピアからどのピアへ中継したか」を記憶する。 
    ↓ 
 あるピアでついにキャッシュにヒットしたら、 
 メッセンジャーのメッセージを found メッセージに置換し、 
 answererID を新たに生成した一意なIDで初期化する。 
 できたメッセンジャーは自分に search メッセージを送ってきたピアに送る。 
    ↓ 
 found メッセージ付きのメッセンジャーを受け取ったピアは inquirerID を調べ、 
 自身が過去に生成したメッセンジャーのものかどうかを確かめる。 
 found メッセンジャーが自分の生成したものでなかったなら 
 過去の中継記録中にそのIDが含まれていないかどうかを調べる。 
 中継記録中に含まれていた場合は中継元に更に中継する。 
    ↓ 
 あるピアでついに found メッセージ付きのメッセンジャーを受信できたなら 
 メッセージ部分を retrieve に書き換えて・・・以下略。 

 timeStamp はメッセンジャーの破棄に用いる。 
 すなわち、一定時間よりも前に生成されたメッセンジャーはその場で廃棄する。 

 続いて各メッセージについて。 
 メッセージは search, found, retrieve, response の四つとする。 
 この四つはこの順序で状態遷移するものでもある。 

 1)search メッセージ 
 レスの検索を行う。フィールドは次の通り。 

   struct SearchMessage{ 
     long  size ; // メッセージサイズを示すバイト数。 
     string type = "search" ; 
     short  hopCountLeft ; 
     string board ; 
     string thread ; 
     resID_t resFrom ; 
     resID_t resTo ; 
   } ; 

 board 板の thread スレの resFrom から resTo までの範囲のレスを探す 
 という意味になる。search メッセージに対しては found メッセージで応答する。 
 見つからなければ返信はせずに search メッセージを増幅してばらまく。 

 2)found メッセージ 
 検索結果の通知を行う。フィールドは次の通り。 

   struct FoundMessage{ 
     long  size ; 
     string type = "found" ; 
     short  resCount ; 
     struct ResInfo{ 
       resID_t resID ; 
       short  resSize ; 
       char  resMD5[16] ; 
     } resInfos[ resCount] ; 
   } ; 

 search メッセージに該当するレスの一覧の情報を返す。 
 この時、必ずしも完全にヒットしていなくてもよい。 
 例えば、resFrom=1, resTo=100 の search に対して 
 1 〜 40 のレスしか持っていなくても返信してよい。 
 found メッセージを受信したピアは次の retrieve メッセージで応答する。 
 ただし、found メッセージ中のハッシュが 2ch.net から取得したものと 
 一致しなかった場合にはこれを無視してよい。 

 3)retrieve メッセージ 
 レス内容の提供を要請する。フィールドは次の通り。 

   struct RetrieveMessage{ 
     long  size ; 
     string type = "retrieve" ; 
     short  resCount ; 
     resID_t resIDs[ resCount] ; 
   } ; 

 提供を要請する ID の列を resIDs に収める。 
 retrieve メッセージに対する返信として 
 ピアは次の response メッセージで応答する。 

 4)response メッセージ 
 レス内容を提供する。フィールドは次の通り。 

   struct ResponseMessage{ 
     long  size ; 
     string type = "response" ; 
     short  resCount ; 
     struct Response{ 
       resID_t resID ; 
       string content ; 
     } reponses[ resCount] ; 
   } ; 

 response メッセージを受信したピアは 
 content から改めてハッシュを計算して照合を行う。 
 この段階でハッシュが一致しなければ 2ch.net 上から直接レスを集める。 

 なお、セッションごとに状態遷移をきちんと管理すること。 
 ありえない状態に属するメッセージを受け取った場合には 
 エラーとみなしてこれを廃棄する。 

 ●ピア間通信はTCP
 558 名前:266 投稿日:01/08/26 16:54
 >>557 
 ありがとうございます:) 
 早速なんですがピア間の通信は 
 TCPよりもUDPの方がよいような気がするんですが 
 UDPだと何か問題は出てきますか? 
 俺の理解の範囲内だと response メッセージで 
 大量のメッセージを一度に送る場合以外は問題ないように思えるんですが 
 穴があったらご指摘ください。 

 559 名前:1 投稿日:01/08/26 16:57
 >>558 
 F/Wを超えないことがある。< UDP 

 560 名前:266 投稿日:01/08/26 17:02
 >>559 
 UDPとTCPでは前者の方がブロックされていることが多い、ということですね。 
 これはADSLとCATVユーザーの環境で一般的な問題にもなりますね。 
 プロバイダ板あたりで聞けば分かるかな? 

 562 名前:1 投稿日:01/08/26 17:09
 CATVはNATを通しているケースもあるので、UDP通らないケースが多いと思います。 
 ADSLはグローバルが多いのかな?(うちはそう。) 

 以上

YukiWiki 1.6.2 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by aki.