goo blog サービス終了のお知らせ 

P2Pとかプログラミング全般とか

P2Pアプリ開発を目指していこうかと。
基本、週末更新なので遅々として進まず。

DHTインスタンスを作る (ソースは分割して掲載 その1)

2008-02-23 22:58:06 | P2P
まず DHT を作るところを。
一応、シンプルに作ってみた(というか、ow.tool.dhtshell を切り張りしたというか…)ので、使いまわせるかと。
アルゴリズムは TCP, Koorde, Recursive で固定。
Koorde は Successor List が少なくてすむ(その代わりホップ数が多い)し、Chord ベースなので churn 耐性が高めというところを買って。
Recursive なのは、Iterative だと何度も接続を繰り返しそうだから。
基本的に接続数は少なくするのが良いっていう貧乏性なのでこういう選択に。
Successor List が大きいとそれだけ色々なノードに接続しに行く可能性が高まり、
切断と接続が繰り返されるんじゃないかな~って心配がある。
アルゴリズムは後々変更するかも。
public class Main implements EmulatorControllable {

    public Writer invoke(int id, String[] args, PrintStream out)
            throws Throwable {
        // TODO 自動生成されたメソッド・スタブ
        // Emulator で起動するとこのメソッドが呼ばれる。つまり、main メソッドは決して呼ばれない。
        return null;
    }

    /**
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        new Main().start(args);
    }
    private void start(String[] args) {

    }

    private DHT<Serializable> initialize(String[] args) throws Exception {
        CommandLine cmd = null;
        try {
            Options opts = new Options();
            opts.addOption("d", "directory", true, "working directory");
            opts.addOption("i", "id", true, "self ID");
            opts.addOption("s", "selfaddress", true, "self IP address");
            opts.addOption("t", "interactive", false, "change to interactive mode");
            opts.addOption("ul", "useLocal", false, "use Local Address(not use Global Address)");
            cmd = new PosixParser().parse(opts, args);
        }
        catch (ParseException e) {
            System.out.println("There is an invalid option.");
            e.printStackTrace();
            System.exit(1);
        }

        String transport = "TCP";
        String algorithm = "Koorde";
        String routingStyle = "Recursive";
        File fWorkDir = null;
        ID selfID = null;
        String statCollectorAddressAndPort = null;
        String selfAddressAndPort = null;
        boolean noUPnP = true;

        boolean join = false;

        String s = cmd.getOptionValue('d');
        if (null != s) {
            fWorkDir = new File(s);
            if (fWorkDir.exists() && fWorkDir.isDirectory()) {
            }else{
                fWorkDir = null;
            }
        }
        if (null == fWorkDir) {
            fWorkDir = new File(".");
        }
        s = cmd.getOptionValue('i');
        if (null != s) {
            selfID = ID.getID(s, s.length() / 2);
        }

        // 待ち受けポート
        selfAddressAndPort = "37845";
        final boolean useLocalAddress = cmd.hasOption("ul");
        if (useLocalAddress) {
            selfAddressAndPort = InetAddress.getLocalHost().getHostAddress() + selfAddressAndPort;
        } else {
            // 自ノードアドレスを得る。
            String[] ipGetPage = {
                "http://www.goo.ne.jp/index.html",
                "http://www.cybersyndrome.net/evc.html",
                "http://www.cman.jp/network/support/go_access.cgi",
            };
            byte[] buf = new byte[1024];
            Pattern ptnIP = Pattern.compile("((\\d{1,3}\\.){3}\\d{1,3})");
            Proxy proxy = Proxy.NO_PROXY;
            for (String host : ipGetPage) {
                try {
                    URL u = new URI(host).toURL();
                    URLConnection uc = u.openConnection(proxy);
                    uc.setReadTimeout(3);
                    InputStream in = uc.getInputStream();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    while (true) {
                        int n = in.read(buf);
                        if (n <= 0) {
                            break;
                        }
                        baos.write(buf, 0, n);
                    }
                    in.close();
                    s = new String(baos.toByteArray(), "ASCII");
                    Matcher m = ptnIP.matcher(s);
                    if (m.matches()) {
                        selfAddressAndPort = m.group(1) + ":" + selfAddressAndPort;
                        break;
                    }
                } catch (Exception e) {
                    // TODO エラー
                }
            }
        }


…まだソースは続く…。

実装する機能

2008-02-20 23:05:44 | P2P
P2Pニコ動キャッシュ共有プログラムに必要な実装機能を書いておこう。

一定時間(1時間?)毎に所持している flv ファイルの名称と自ノード情報を put する。

頻繁な離脱(churn)への耐性をつけるため、一定時間毎に put する。
put の key は sm???? をハッシュ値にしたもの、value は自ノードの IDAddressPair かな。
登録するのはエコノミー以外の flv、かつ完全ファイルのみ、かな。

目的の flv ファイルの情報を get し、要求先ノードを調べる。

要求先ノードに flv ファイルの名称と取得範囲を伝える。

これは put ではなくメッセージ送信になる。できれば put と同じように DHT のルーティングで届けるほうがいいかも。
直接送信するとそのノードに接続することになるけど、できれば接続するノードは Successor List にあるノードだけにしたほうが put するときと相性が良さそうだから。
要求は最大でも 64kb 単位で行う。flv は通常 数 mb あるから、それを一気に送ることは無理。細切れで取得する。

要求メッセージを受け取ったら、対象 flv ファイルの情報をメッセージにつめて要求元ノードに送信する。

これは DHT ルーティングせず直接送る予定。要求そのものは大きくても数 kb のメッセージだが、実際のデータは細切れにしても 64 kb 以上。これをルーティングしたらネットワーク帯域を食いすぎる。


だいたいこんな機能を実装予定。
よく見直したら、これって簡易的な P2P ファイル交換機能…。
…ま、flv 限定ってことで。