仙石浩明の日記

2006年7月10日

一つのIPアドレスで djbdns (tinydns, dnscache) を走らせる (3) dnscache で別ポートを使う

前回は、tinydns を IP アドレス指定せずに起動したいケースについて述べた。 前々回で述べたように、 djbdns はネームサーバ tinydns と、 キャッシュサーバ dnscache が完全に分離した独立のプログラムになっていることが 大きな特徴であるが、 tinydns を IP アドレス指定せずに起動しようとすると、 同じポート番号を使う dnscache を起動することができなくなってしまう。

そもそも論で言えば、 ネームサーバとキャッシュサーバは全く異なるサービスを行なうサーバなのだから、 同じポート番号を使うこと自体が間違っているのである。 もしキャッシュサーバが 53番以外のポートを使うのであれば、 tinydns も dnscache も IP アドレスを指定せずに同じマシンで起動できるし、 これ以上シンプルな解決策はないであろう。

ならば dnscache を 53番とは異なるポートで起動しよう。 ただし、dnscache は 53番ポートを bind(2) するように ハードコーディングされているので、 若干パッチをあてる必要がある。

--- dnscache.c.org        Mon Feb 12 06:11:45 2001
+++ dnscache.c        Sun Jul  9 06:43:23 2006
@@ -390,6 +390,7 @@
 {
   char *x;
   unsigned long cachesize;
+  unsigned long port;
 
   x = env_get("IP");
   if (!x)
@@ -397,16 +398,19 @@
   if (!ip4_scan(x,myipincoming))
     strerr_die3x(111,FATAL,"unable to parse IP address ",x);
 
+  x = env_get("PORT");
+  if (x) scan_ulong(x,&port); else port = 53;
+
   udp53 = socket_udp();
   if (udp53 == -1)
     strerr_die2sys(111,FATAL,"unable to create UDP socket: ");
-  if (socket_bind4_reuse(udp53,myipincoming,53) == -1)
+  if (socket_bind4_reuse(udp53,myipincoming,port) == -1)
     strerr_die2sys(111,FATAL,"unable to bind UDP socket: ");
 
   tcp53 = socket_tcp();
   if (tcp53 == -1)
     strerr_die2sys(111,FATAL,"unable to create TCP socket: ");
-  if (socket_bind4_reuse(tcp53,myipincoming,53) == -1)
+  if (socket_bind4_reuse(tcp53,myipincoming,port) == -1)
     strerr_die2sys(111,FATAL,"unable to bind TCP socket: ");
 
   droproot(FATAL);

すなわち、環境変数「PORT」にポート番号を設定した場合は、 53番ポート番号の代わりに設定されたポート番号を使えるようにする。 例えば 2053番ポートで dnscache を起動する。 もちろんリゾルバは、こんな事情はお構い無しに 53番ポートへ問合わせるので、 それを 2053番ポートへ振り向ける (リダイレクトさせる) 必要がある。

Linux には、 パケット フィルタリング フレームワーク があって、 ネットワーク アドレス変換を自在に行なうことができる。 だから、53番ポートへのアクセスを 2053番ポートへリダイレクトする、 などということは iptables コマンドを実行するだけで手軽に実現できる。

例えば、dnscache と同じマシン上のリゾルバから 53番ポートへの接続を、 2053番ポートへリダイレクトするなら、

iptables -t nat -A OUTPUT -j REDIRECT -p udp --dport 53 --to-port 2053 \
        -s 127.0.0.1 -d 127.0.0.1

などと iptables を実行するだけである。 「-p udp --dport 53」の部分で、 UDP 53番ポートへのアクセスが対象であることを指定し、 「--to-port 2053」の部分で、 リダイレクト先が 2053番ポートであることを指定している。

また、「-s 127.0.0.1 -d 127.0.0.1」の部分が、 接続元 (つまりリゾルバ) と接続先 (つまり dnscache) の IP アドレスの指定である。 接続元が LAN 内の他のマシンの場合も許可するなら、 この部分を例えば「-s 192.168.1.0/24 -d 192.168.1.1」に変更し、 「OUTPUT」の代わりに「PREROUTING」チェインを指定して iptables を実行すればよい (後述)。

さて、これだけだと実は問題がある。 dnscache は当然のことながら自ドメインのホスト名を解決するには 同じマシン上の tinydns へアクセスする必要があるのだが、 上記のように iptables を実行すると、 この dnscache から tinydns へのアクセスまでリダイレクトしてしまう。 すなわち dnscache が localhost の 53番ポートへ、 自ドメインに関する問合わせを行なうと、 それが 2053番ポートへリダイレクトされ、 結果 dnscache (つまり自分自身) に届いてしまう。 これでは自ドメインのホスト名の解決ができない。

したがって、dnscache からのアクセスの場合だけは、 リダイレクトが行なわれないようにしなければならない。 これを実現するには、 iptables のパラメータに「-m owner ! --uid-owner Gdnscache」 を追加すればよい。 これは、アクセス元のユーザが「Gdnscache」ならばリダイレクトを行なわない、 という指定であり、 Gdnscache は dnscache を実行しているユーザID である。

以上をまとめると、 次のような sh スクリプトになる。 これをマシンのブート時に実行すればよい。

#!/bin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin
nsredirect="-t nat -j REDIRECT --dport 53 --to-port 2053"
iptables -p udp $nsredirect -A OUTPUT -s 127.0.0.1 -d 127.0.0.1 \
        -m owner ! --uid-owner Gdnscache
iptables -p tcp $nsredirect -A OUTPUT -s 127.0.0.1 -d 127.0.0.1
if [ -n "$INNER_NETWORK" -a -n "$INNER_DNSCACHE" ]; then
        nsredirect="$nsredirect -A PREROUTING \
                -s $INNER_NETWORK/$INNER_NETMASK -d $INNER_DNSCACHE"
        iptables -p udp $nsredirect
        iptables -p tcp $nsredirect
fi

$INNER_NETWORK」と「$INNER_NETMASK」に、 LAN のネットワークアドレス (例えば 192.168.1.0) とサブネットマスクを それぞれ指定する。 また、「$INNER_DNSCACHE」は キャッシュサーバ (つまりこのマシン) の IPアドレスである。

なお、Linux のパケット フィルタリングでは、
接続元が同一ホストの場合は OUTPUT チェインが使われるので、
-s 127.0.0.1」を指定するときは「-A OUTPUT」を指定して OUTPUT チェインへ追加し、
接続元が LAN 内の他のマシンの場合は PREROUTING チェインが使われるので、
-s $INNER_NETWORK/$INNER_NETMASK」を指定するときは 「-A PREROUTING」を指定して PREROUTING チェインへ追加している。

Filed under: システム構築・運用 — hiroaki_sengoku @ 06:43
2006年7月9日

一つのIPアドレスで djbdns (tinydns, dnscache) を走らせる (2) IPアドレス指定しないサービス起動

前回は djbdns の特徴について述べた。 djbdns の大きな特徴は、 キャッシュサーバ (dnscache) とネームサーバ (tinydns) が分離している、 という点であり、 ネームサーバだけを不特定多数に対して公開することにより、 BIND など他のネームサーバがかかえている潜在的リスクを完全に回避している。

dnscache と tinydns を走らせるための、 固定的な IP が確保できるのであれば話は簡単なのであるが、 複数の (固定的な) IP アドレスを使いにくいマシン環境もある。

例えばノートPC は、移動中など、スタンドアロンで動かすこともあり、 この場合、IP アドレスは 127.0.0.1 の一つだけである。 LAN に接続したり、あるいはダイアルアップ接続すると、 もう一つ IP アドレスを持つことになるが、 この IP アドレスは固定ではなく、 接続のたびに動的に割当てられることが多いだろう。 仮に毎回同じ IP アドレスが割当てられるのだとしても、 スタンドアロン状態の時は、 その IP アドレスが利用できないという点で、 固定的な IP アドレスが利用できるとは言いがたい。

Linux 等では alias IP アドレスを設定することによって 固定的に IP を割当てておくこともできる。 例えば loopback インタフェース lo に対して

onohara:/root # ifconfig lo:0 127.0.0.2

などと別の IP アドレスを追加することができる。 マシン内部で利用するサービスならこれでもいいが、 外部に対して公開するサービスではこの方法は使えない (ノートPC で外部にサービスしてどうするん?という突っ込みは言わないお約束 ;)。

ノートPC 以外でも、 例えば小規模サイト (家庭LAN など) における ゲートウェイマシンなどにおいても、 昨今だとインターネットへの接続は PPPoE を使うことが多いだろう。 グローバル IP アドレスは接続時のみ割当てられる。 サイト外に公開するネームサーバは、 このグローバル IP アドレスで動かすのが自然であるが、 PPPoE 接続が切れている場合にどうするか考えておく必要がある。

ノートPC にしろゲートウェイマシンにしろ、 外部に対して接続しているときのみ割当てられる IP アドレスを利用しようとすると、 接続時のみ tinydns を起動する、 という方法を採らざるを得ない。 たとえば接続が成功したときに実行されるスクリプト (/etc/ppp/ip-up など) で tinydns を起動し、 接続が切れたときに実行されるスクリプト (/etc/ppp/ip-down など) で tinydns を終了させる、 という方法が一般的だろう。

しかしながらこの方法だと、 接続が切れているときは tinydns も動いていないわけで、 サイト内に対して別途 tinydns を立ち上げる必要がある。 また、 接続のたびにサーバプログラムを起動するということは、 それだけトラブルの可能性が高まるということであり、 できればもっとシンプルにしたい。 対外サービスを行なうサーバプログラムには、 常に安定して動いていてほしいわけで、 起動・停止を繰り返す運用よりは、 ずーっと立ち上げっぱなしの方が好ましいだろう。

UNIX の場合、 動的に IP アドレスを割当てられたときに、 サーバプログラムで IP アドレスを bind(2) しなおさないで済む方法というと 一つしかない。 つまり IP アドレスを指定せず (INADDR_ANY) に bind(2) する方法である。

senri:/root # netstat -nap
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address      Foreign Address    State      PID/Program name
        ...
udp        0      0 :::53              :::*                          1240/tinydns
tcp        0      0 0.0.0.0:53         0.0.0.0:*          LISTEN     1242/tcpserver
        ...

「Local Address」に「:::53」とか「0.0.0.0:53」と出ているのが、 IP アドレスを指定せずに走らせているサーバプログラムである。 このようなサーバプログラムは、 マシンに割当てられているどの IPアドレスに対する接続も受け付けることができる。 つまり新たに動的に IPアドレスが追加されても、 サーバプログラムを立ち上げ直す必要がない。

だから tinydns は IPアドレスを指定せずに、 つまり環境変数 IP に 0.0.0.0 (INADDR_ANY) を設定して立ち上げることが望ましい。

ところが、このようにしてしまうと、当然のことながら 同じ 53番ポートを使う dnscache を同じマシンで立ち上げることが できなくなってしまう。

そもそも、キャッシュサーバ (dnscache) とネームサーバ (tinydns) では 目的が違うのにもかかわらず、 同じポート番号 53番を使うのが問題なのである。 最初から別のポート番号を割当てておけば、 このような問題で悩まなかったものを... RFC 883 が悪い~
と言っても始まらない (^^;) ので、 なんとか tinydns と dnscache を IP アドレスを指定せずに立ち上げる方法を 考えてみたい。

続きは次回に...

Filed under: システム構築・運用 — hiroaki_sengoku @ 07:10
2006年7月8日

一つのIPアドレスで djbdns (tinydns, dnscache) を走らせる (1) djbdns の特徴

djbdns は、 とてもシンプルなネームサーバなので、 動作が予測しやすいという特徴を持っている。 複雑なプログラムにありがちな、 謎な現象とも無縁。 ネームサーバというと BINDが有名だが、 BIND はとても巨大なプログラムで、 特に高負荷時に理解しがたい挙動をする。 私は 3年半ほど前に BIND の異常動作 (高負荷環境下だとサービス起動に異常に時間がかかる) で徹夜する羽目に陥って以来、 BIND を捨てて djbdns を使うようになった。

djbdns の大きな特徴の一つに、 キャッシュサーバ (dnscache) とネームサーバ (tinydns) が分離している、 という点がある。 キャッシュサーバ、すなわちリゾルバからの問合わせを受けて、 他のネームサーバに再帰的に問合わせを行なうサーバは、 不特定多数からの問合わせを受付けるべきではない。 なぜなら、キャッシュサーバはその仕組み上、 攻撃に対して脆弱であり、 不特定多数に対してオープンにするのであれば、 嘘のレコードを覚え込まされてしまう 恐怖に怯え続けなければならない。

一方、ネームサーバは本来的に不特定多数に対してサービスすべきものである。 他ドメインからの問合わせ (主に他ドメインのキャッシュサーバからの問合わせ) に対して答えなければ役目を果たせない。 つまり、

  • キャッシュサーバは自ドメインのユーザからの問合わせに答えるサーバ
  • ネームサーバは他ドメインからの問合わせに答えるサーバ

であって、全く異なる役目のサーバである。 両機能を (BIND のように) 一つのプログラムで実現することは 大変なリスクをともなう。

私も djbdns に乗り換える前は BIND を使っていたのだが、 キャッシュサーバとネームサーバを分離し、 セキュリティを向上させるために様々な工夫をした。 この辺りの顛末は、 日経Linux に書いた連載の中でも紹介している:

2000年 5月号 第2回 「ネーム・サーバ (前編)」 pp143-148 (HTML 版)
2000年 6月号 第3回 「ネーム・サーバ (後編)」 pp133-140 (HTML 版)

djbdns だと、この連載で書いたような工夫をしなくても、 同等以上のセキュリティをデフォルトで実現できるので、 とても楽である。

キャッシュサーバとネームサーバそれぞれを別のマシンで動かすのであれば、 素直に djbdns を動かすだけで完璧なのであるが、 一台のマシンで両者のサーバを動かそうとすると、 少々工夫が必要である。 もし、そのマシンが複数の NIC (ネットワーク インタフェース カード) を 持っていて、 各 NIC に固定的に IP アドレスを割当てているなら、 話は簡単である。 異なる NIC それぞれに、 キャッシュサーバないしネームサーバをそれぞれ立ち上げればよい。 ところが IP アドレスが固定でない場合は少しやっかいである。

続きは次回に...

Filed under: システム構築・運用 — hiroaki_sengoku @ 08:34
2006年7月6日

ロングテール戦略が格差社会を生む: 必要は発明の母 hatena_b

仮説: ロングテール戦略が格差社会を生む の検証の二回目 (全七回を予定)。

必要は発明の母

格差が広がりつつあることの根拠として、 親の資金力が子供にかけられる教育費に影響を与え、 子供の知能に影響する、という点があげられることがあるが、 果たしてそうだろうか? 確かに、お金に糸目をつけなければ いくらでも(授業料が)高い教育を受けさせることができる。 いくらデキの悪い子でも、 教えたぶんくらいは学力が上がるだろう。 しかしながら学力と知能は違う。 知能とは考える力であり、 いい学校にいけば身につけられる、 というものでもない。

学びて思わざれば則ち罔し

教わるだけで考えなければダメ、とは 論語以来くり返し言われ続けてきていることであるが、 考える訓練を学校で行なっているかと言えば、 なかなか心もとないものがある。 少なくとも私の経験だと、 考える習慣というのは学校とは関係のないところで身につけたような気がする。

どういうときに考える習慣が身についたかと言えば、 それは何か不足しているときである。 何か不便なことがある、 あるいは何かやりたいことがあるのだけどできない。 様々な制約をどうやって乗り越えようかと思案しているときに、 ついつい深く考え込む。

私が子供の頃というと高度成長期が終わった頃なので、 世の中にモノは溢れていた。 だから「不足」というとおこがましいのであるが、 当時は大量生産の時代なので、 少数のニーズは切り捨てられていた。 また、一億総白痴化の道具と言われたテレビも、 視聴率至上主義で少数のニーズには見向きもしていなかった。 つまり、 モノが溢れていると言っても画一的な製品ばかりだったし、 テレビなどのマスメディアが提供するサービスも画一的だった。 子供心にも、テレビはつまらない番組ばかりという印象を持った。

だから、好奇心旺盛な子供にとって工夫の余地はいたるところにあった。 買うより作った方が早い、そういう時代だったし、 小学生が電子工作に夢中になるのも珍しいことではなかった。 小学生でもいろいろ考えれば、 大人が驚くような成果を誇示することが可能だった。

「知」に対する渇望

プログラマを目指すのに適した時代、適していない時代」で書いたように、 私がプログラミングを学ぼうとした時代は制約や不足だらけだった。 そもそも入門書が無い。 少なくとも街の本屋にはコンピュータ関係の本は皆無だったし、 大阪梅田の 紀伊國屋書店旭屋書店でさえ、 コンピュータ関連書籍のコーナと言えば、せいぜい本棚一つくらいのものだった。 そんな希有な本棚を見つけ出せたとしても、 現在みたいに手取り足取り教えてくれる入門書なんてあるわけがなく、 大学の専門課程の学生向けの専門書を、 わずかな手がかりをもとに当時中学生だった私が読み解いていくのである。 まさに「読書百遍、意自ら通ず」の世界である。

そんな私が、初めて 八重洲ブックセンターを 訪れたときの感慨を理解して頂けるだろうか? 大げさに聞こえるだろうが、まさに砂漠で一杯の水を見つけたような気分だった。 一日中ここですごしたいと思ったものだ。

そうやってあちこちを探しまわって なんとか入手した 6502 のデータシートに記載されていた ニーモニック表を手がかりに、 まるで暗号解読をするように一命令づつその動作を想像し、 ついにはハンドアセンブルできるようになった時の達成感、 そしてハンドアセンブルして作ったバイナリコードを PET 2001 に打ち込んで実行し、 BASIC とはケタ違いのスピード ──まさに一瞬だった── を 目の当たりにしたときの感動は、 今でもありありと思い出すことができる。

「知」に対する渇望があるからこそ、 人は学び考えるのだろうと思う。 渇望するより先に与えられてしまったとしたら、 果たしてそれを学び考えようとするだろうか? 少なくとも若かった頃の私にそれができたかというと、 はなはだ自信がない。 いつでも学べると思うと、 「時間ができたら勉強したい」と 後回しにしてしまいそうな気がするのである。

不足(ニーズ)あるところに商機あり

多品種少量生産の時代になって久しい。 どんなニッチなニーズでも、 それを満たす製品ないしサービスがたちどころに開発されて提供される。 しかも IT技術によって全国津々浦々、どこにいてもその恩恵を受けられる。 やっとの思いで上京して八重洲ブックセンターに行く必要はないのである。 かゆいところに手が届くサービスが湯水のように提供されているのに、 どうして不足を感じることができるだろうか。 まして「渇望」とは無縁であろう。 世の中これだけ便利になってしまうと、 どうやって工夫すればいいのだろう? テレビが成し得なかった「一億総白痴化」を IT技術が達成してしまうのだろうか。

いや、そんなことはない、 インターネットの時代では、 消費者は単に消費するだけでなく、 自ら情報を発信していく、 生産者的かつプロフェッショナルな消費者 つまりプロシューマだ、 という人がいるかも知れない。 それはその通りだろう。 一部の消費者は「消費者」の枠に留まらず、 どんどん活躍の場を広げていくことだろう。 しかし、 そういった活躍をするのにも知能は必要である。 身近なところで考える訓練を積むことなく、 いきなりインターネットの世界に晒されては、 情報発信以前に、 あっと言う間に魑魅魍魎の餌食になるだろう。

Filed under: 自己啓発 — hiroaki_sengoku @ 06:29
2006年7月1日

プログラマを目指すのに適した時代、適していない時代 hatena_b

プログラマの道を目指すのに適した時代、適していない時代、 というのがあるように思う。 もちろんプログラマに限らず、あらゆる職種、それぞれについて、 適した時代というのがありそうだ。 最初に断っておくが、 適していない時代だからといって、その職種を目指すな、と言っているわけではない。 ただ単に、適していない時代であることを意識し、 適していないことを覚悟して ;-)、その道を目指すべきだ、という意味である。

現代は、プログラマを目指すのには適していない時代だとつくづく思う。

そんな馬鹿な、インターネットの普及によって、何でも簡単に調べられて、 その気さえあればいくらでも高度な勉強ができて、 いくらでもプログラマとしてのスキルアップができるではないか、

という反論が聞こえてきそうであるが、 もうしばらく黙って私の話を聞いて欲しい。

自分なりに体系化するセンス」で、長久氏曰く:

「仙石浩明の日記」版「断片的な知識と体系的な知識」を見ると、 こういう学生時代を過ごして来た人って、 私の知人を見る限り 「未踏」級なんですよね。 で、やっぱり1回目の未踏に採択されています。 また、学習指導要領的には、 私の1世代前で、最も勉強が難しかった世代です。 今と違って、誰でもプログラマーになれた時代でもありません。 恐らく、仙石氏の同世代で普通のプログラマーって、 私の世代の普通のプログラマーより、 はるかにパフォーマンスが高いはずです。 更に世代を下がって、今の20代前半の普通のプログラマーって、 仙石氏の世代から見て、ありえない人たちに見えるのではないかと思います。
あまり議論されているのを見たことないのですが、 世代の違いって、すごく大きい気がします。 ソフトウェア技術者って、 仕事でハンマーとか使わないから(?)、 後輩に優しかったり、 職場に同じ年代が集まりやすいので、 世代を超えて積極的に交わろうとしなかったり、 世代間の断絶みたいなものがある気がするのです。 なので、私は、プロレスのように、積極的に世代闘争するべきだと思うんですよね。

「未踏」というのは、 「天才プログラマー/スーパークリエータ」を発掘支援することを目的に IPA が実施している 事業で あるが、 採択された他の方がどうだかはよく分からないが、 少なくとも私自身はとても「天才」とか「スーパー」とか呼ばれるようなレベルでは 全然ないと思う。 これは決して謙遜というわけではなくて、 自身がそういうレベルではないと思うからこそ、 プログラミングのみに集中するのではなく、 「取締役CTO」みたいなことをやったり、 マーケティングをかじってみたりと、 プログラマとしては道を踏み外したことを専らやっているわけだ。

そんな私が、いやしくも IPA のような権威に認めてもらえるように なってしまったのは、 ひとえに私がプログラミングを始めた時代が、 プログラマを目指すのに適した時代だった、 という幸運に恵まれたためだったからと思う。 私が初めてプログラムを書いたのは、 今から 30年近く前、中学1年生の時である。 1978年当時は、まさに長久氏がおっしゃる通り、 今と違って、誰でもプログラマーになれた時代ではなかった。

そもそもコンピュータ自体がまだまだ珍しい存在で、 私自身、もし中学校に「マイコン部」が無かったら、 コンピュータに出会うのはもっと後になってからだったとは思う。 コンピュータに出会う確率が低かった、 という意味で誰でもプログラマーになれるわけではなかったわけであるが、 それ以上に、当時の「マイコン」には少なくとも普通の人にとっては、 なんの魅力も感じられない代物だった、というのが重要な点である。

今と違い当時の「マイコン」は、大したことはできなかった。 高々 20Kバイトの BASIC インタープリタに、 最大 8Kバイトの RAM に記憶させた BASIC プログラムを実行させて、 40x25 キャラクタディスプレイ (つまりビデオRAM はわずかに 1Kバイト! もちろん表示できるのは半角文字だけである) に 表示させてできることなぞタカが知れている。 慣れない BASIC言語でプログラム書いてはバグに悩まされ、 散々苦しんだ挙げ句に得られる見返りは、あまりに少なかった。 自分で言うのもアレだが、 こんな何の役にも立たないものが好きになるのは、 よっぽどの物好きだけだったろう。

実際、私の同級生の中には、 プログラミングに興味を持って BASIC 言語を学ぼうとした人も沢山いたが、 大多数の人は何をすき好んでこんな七面倒くさい「言語」を学ぶのか、 到底理解できず、すぐ興味が別のものへ移っていった。 中学を卒業する頃、まわりを見渡してみると、 BASIC 言語を使いこなすレベルまで到達したのは私だけだったと記憶している。 私以外の同級生が BASIC 言語も使えないくらい低能だった、 というわけでは決してない。 それどころか私より明らかに頭がいい人も沢山いた。 それでも BASIC 言語一つ覚えられなかったのは、 単にプログラミングをするということに意義を見いだせなかっただけに過ぎない。 彼らが現在の中学生だったなら、 余裕で Web 2.0 時代のプログラミングをバリバリこなしていただろう。

つまり、誰でもプログラマーになれた時代ではなかったというよりは、 誰もプログラマーになろうとは思いもしなかった時代だった。 しかし、逆説的ではあるが、 苦労に見合うリターンが全く得られないからこそ、 自分がプログラミングが好きだということを確認できたという点で、 当時は「プログラマを目指すのに適した時代」だったと思う。

それに比べ、 現在のように少しでもプログラミングができれば給料までもらえてしまう、 ある意味プログラマが必要以上に優遇されている世の中では、 好きだからプログラミングをするのか、 それとも単に食うために(仕方無しに)プログラミングするのか、 曖昧になってしまうわけで、 「プログラマを目指すのには適していない時代」なのだと思う。

長久氏がおっしゃるように、 「仙石氏の同世代で普通のプログラマーって、 私の世代の普通のプログラマーより、 はるかにパフォーマンスが高いはず」というのは (実際に統計をとったわけではないが実感としては) 正しくて、 その原因は、 当時の「普通」のプログラマは、 みな例外無くプログラミングが三度の飯より好きだったし、 プログラミングに向いている人だけがプログラミングをやっていた、 ということにあるのだろうと思う。

昔話に終始していては、現在の若い人たちの参考にならないだろうから、 この話を現在に適用すれば、次のようになるだろう:

今の時代は、 プログラミングをすれば充分すぎる見返りが得られるが故に、 自分がプログラミングに向いているのか、 あるいは単に見返りのためにプログラミングをしているのか見極めるのが、 とても困難な時代である。 プログラマを目指すのもいいが、 向いていないことを後になって自覚して 「35歳で定年を迎える」ことにはなってほしくない。 現在は明らかにプログラマを目指すのには適していない時代である。 では何を目指すのに適した時代だろうか? 1978年当時の「マイコン」に相当するものが、 今の時代にもきっとあるはずである。 若い感性でそれを見つけ出し、 誰もが目指さないからこそチャンスがあるんだと信じて、 自分に向いていることをどこまでも追い求めて欲しい。

Filed under: 技術者の成長 — hiroaki_sengoku @ 08:41
2006年6月29日

jabber サーバの死活確認スクリプト

jabber.jp と Google Talk との相互接続開始」で jabber.jp の紹介をしたのが原因というわけでもないのだろうが、 一時的に jabber サーバが過負荷になってサービス不能状態に陥ってしまった。 この jabber.jp は KLab のサーバマシン群の中では低性能なマシンを使っていたので、 この機会にと、もう少しマシなマシンへ引越しさせた。 が、負荷の問題というよりは、サーバプログラム自体に、 なにかのタイミングでハングするバグがあるようだ。 他のソフトウェアへの乗り換えも含めて対策を検討中であるが、 とりあえずハングしていないかの死活確認は必須だろう。

まず CPAN から Net::Jabber をインストール。 「Google Talk を流れるデータを見る」に、
「Net::Jabberは,インストールしようと思ってもmake testでひっかかってしまってうまくインストールできません.」と書いてあったのが 気になりながら (^^;) 作業していると...

cpan> install Net::Jabber(改行)
        ...
---- Unsatisfied dependencies detected during [R/RE/REATMON/Net-XMPP-1.0.tar.gz] -----
    XML::Stream
Shall I follow them and prepend them to the queue
of modules we are processing right now? [yes] (改行)
Running make test
        ...
t/buildxml......ok
t/load..........ok
t/parse_node....ok
t/parse_tree....ok
t/tcpip.........ok
t/tcpip2ssl.....ok 2/3

ありゃ、止まってしまった。 XML-Stream-1.22/t/tcpip2ssl.t を見ると、

my $status = $stream->Connect(hostname=>"obelisk.net",
                              port=>5223,
                              namespace=>"jabber:client",
                              connectiontype=>"tcpip",
                              ssl=>1,
                              timeout=>10);

などと書いてある。 つまり、jabber サーバである「obelisk.net」を相手に 接続テストを行なおうとして止まってしまっている。 おそらく obelisk.net が相手にしてくれないのだろう (5222番ポートの方は相手をしてくれるようだ)。 とりあえず obelisk.net の代わりに手元の jabber サーバを指定して、 テストを成功させ、無事インストール完了。

とりあえず、さくっと死活確認スクリプトを書いてみる:

#!/usr/bin/perl
@RCPTS = ('jabber-error@gcd.org',);
use Net::Jabber qw(Client);

&ckjabber("jabber.gcd.org", 5222, "test", "XXXXXXXX", "ckjabber.$$");
&ckjabber("jabber.jp", 5222, "test", "YYYYYYYY", "ckjabber.$$");

sub ckjabber {
    my ($server, $port, $username, $password, $resource) = @_;
    my $client = new Net::Jabber::Client();
    my $connected = 0;
    my $authenticated = 0;
    my $recv_subject;
    my $recv_body;
    my $subject = "check $server";
    my $body = "This is a test message from $resource.";
    my $onConnect = sub { $connected++; };
    my $onAuth = sub {
        $authenticated++;
        $client->MessageSend(to => "$username\@$server/$resource",
                             subject=> $subject, body => $body, );
    };
    my $onMessage = sub {
        my ($sid, $message) = @_;
        $recv_subject = $message->GetSubject();
        $recv_body = $message->GetBody();
        $client->Disconnect();
    };
    $client->Connect(hostname => $server);
    $client->SetCallBacks(onconnect => $onConnect, onauth => $onAuth,
                          message => $onMessage, );
    $client->Execute(username => $username, password => $password,
                     resource => $resource,
                     hostname => $server, port => $port,
                     register => 1,
                     connectsleep => 0, connectattempts => 1, );
    my $error;
    if (! $connected) {
        $error = "can't connect to $server";
    } elsif (! $authenticated) {
        $error = "authentication failure";
    } elsif ($recv_subject ne $subject || $recv_body ne $body) {
        $error = "get '$recv_subject' & '$recv_body'";
    }
    if ($error) {
        print STDERR "$server error\n$error\n";
        &mail("$server error", localtime(time) . "\n$error\n", @RCPTS);
    }
}

sub mail {
    my ($subject, $body, @rcpts) = @_;
    open(INJECT,"|/var/qmail/bin/qmail-inject " . join(" ", @rcpts)) || die;
    print INJECT "From: root\nTo: ", join(", ", @rcpts), "\n",
        "Subject: $subject\n\n$body";
    close(INJECT);
    if ($? << 8) {
        print STDERR "Fail to send mail to ", join(", ", @rcpts), "\n";
        exit 1;
    }
}

自分自身にメッセージを送ってみて、 同じ文面が返ってくるか確認するだけの単純なテストスクリプトだが、 jabber サーバがハングしたら検知してメールを送ってくれるだろう。 とりあえず 5 分に一度実行するように cron に仕掛けた。

Filed under: システム構築・運用 — hiroaki_sengoku @ 07:44
2006年6月23日

jabber.jp と Google Talk との相互接続開始 hatena_b

jabber.jpGoogle Talk と 相互接続できないのが某所で問題になっている。」 昨日、そんな声が社内から聞こえてきました。 jabber.jp というのは 2001年6月のサービス開始以来、 KLab で運用している jabber (通信に XMLプロトコル XMPP を使う、 インスタント メッセージング サービス) サーバです。 KLab 社内公式 IM (インスタント メッセンジャー) として大いに活用していますが、 社外のかたにも開放しています。

その時は、 「え? Google ? あそこって他サイトとの相互接続ってやってなかったんでは?」 と、思わず答えてしまいましたが、 いつのまにか 相互接続を開始していたんですね。 知らなかった... orz
jabber.org などとは 相互接続できていたので、 Google Talk と接続できないのはアチラの問題、と思い込んでいました (_O_)。

多くの方々に利用して頂いている jabber.jp で調査を行なうよりは、 (落ちても誰も文句言わない ;) 自宅サイト gcd.org も Google Talk と接続できないという 問題をかかえていたので、gcd.org で調査を始めました。

通信できないときに最初にすべきことと言えば、 まずはパケットが届いているか調べることですね。 tcpdump でパケットダンプを取りつつ、 Google Talk (gmail.com) に jabber クライアントでログインして GCD (jabber.gcd.org) へチャットしてみました。

senri:/home/sengoku # tcpdump -i ppp0 port 5269
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ppp0, link-type LINUX_SLL (Linux cooked), capture size 96 bytes
07:07:11.672591 IP iproxy.google.com.32489 > gcd.org.5269: S 2133894537:2133894537(0) win 5720 <mss 1430,sackOK,timestamp 379820136 0,nop,wscale 0>
07:07:13.004593 IP gcd.org.5269 > iproxy.google.com.32489: S 1097254147:1097254147(0) ack 2133894538 win 5608 <mss 1414,sackOK,timestamp 401538947 379820136,nop,wscale 2>
07:07:11.837330 IP iproxy.google.com.32489 > gcd.org.5269: . ack 1 win 5720 <nop,nop,timestamp 379820153 401538947>
07:07:11.837527 IP iproxy.google.com.32489 > gcd.org.5269: P 1:142(141) ack 1 win 5720 <nop,nop,timestamp 379820153 401538947>
07:07:11.837574 IP gcd.org.5269 > iproxy.google.com.32489: . ack 142 win 1670 <nop,nop,timestamp 401538988 379820153>
07:07:11.837762 IP gcd.org.5269 > iproxy.google.com.32489: P 1:187(186) ack 142 win 1670 <nop,nop,timestamp 401538988 379820153>
07:07:12.002559 IP iproxy.google.com.32489 > gcd.org.5269: . ack 187 win 5720 <nop,nop,timestamp 379820169 401538988>
07:07:12.003738 IP iproxy.google.com.32489 > gcd.org.5269: P 142:242(100) ack 187 win 5720 <nop,nop,timestamp 379820170 401538988>
07:07:12.046764 IP gcd.org.5269 > iproxy.google.com.32489: . ack 242 win 1670 <nop,nop,timestamp 401539040 379820170>
07:07:13.486820 IP gcd.org.41294 > 216.239.57.83.5269: S 1003009747:1003009747(0) win 5656 <mss 1414,sackOK,timestamp 401539400 0,nop,wscale 2>

最初 Google 側から GCD の 5269番ポートへ接続があって、 それに答えて GCD から Google へ dialback 接続を行なう... ところが、それに対する応答が無い。 実際、netstat で調べてみると SYN_SENT のままです。

senri:/home/sengoku # netstat -nap | grep s2s
tcp        0      0 0.0.0.0:5269            0.0.0.0:*               LISTEN      14525/s2s
tcp        0      1 60.32.85.216:41294      216.239.57.83:5269      SYN_SENT    14525/s2s
...

見るからに、216.239.57.83 へ接続を試みていることが間違いのようです。 216.239.57.83 というのは gmail.com の A レコードの一つですね。

senri:/home/sengoku % host gmail.com.
gmail.com has address 64.233.161.83
gmail.com has address 216.239.57.83        ←コレ
gmail.com has address 64.233.171.83
gmail.com mail is handled by 50 gsmtp163.google.com.
gmail.com mail is handled by 50 gsmtp183.google.com.
gmail.com mail is handled by 5 gmail-smtp-in.l.google.com.
gmail.com mail is handled by 10 alt1.gmail-smtp-in.l.google.com.
gmail.com mail is handled by 10 alt2.gmail-smtp-in.l.google.com.

では、jabber サーバ間の通信では接続先をどのように探せばよいのだっけ、と 調べてみると、 SRV レコードに サーバのホスト名とポート番号を 登録しておくことになっているようです。 以前は A レコードを使っていたような気がするのですが、 A レコードを直接使ってしまうと、 jabber ID (JID) のドメイン名と jabber サーバのホスト名を一致させる必要があって 柔軟性を欠くから、 SRV レコードに変更したということなのでしょう。

私の自宅サイトのような小規模サイトなら jabber.gcd.org というホスト名で jabber サーバを立ち上げることはさほど問題ではありませんが、 Google のような大規模サイトだと、gmail.com というホスト名で jabber サーバを立ち上げてしまうと運用が面倒なことになりそうです。 gmail.com の SRV レコードを引いてみると、 xmpp-server.l.google.com という応答が返ってきました。 つまり (JID のドメイン名である) gmail.com とは 異なるサーバ xmpp-server.l.google.com で jabber サーバを動かしているということです。

senri:/home/sengoku % host -t srv _xmpp-server._tcp.gmail.com.
_xmpp-server._tcp.gmail.com has SRV record 5 0 5269 xmpp-server.l.google.com.
_xmpp-server._tcp.gmail.com has SRV record 20 0 5269 xmpp-server1.l.google.com.
_xmpp-server._tcp.gmail.com has SRV record 20 0 5269 xmpp-server2.l.google.com.
_xmpp-server._tcp.gmail.com has SRV record 20 0 5269 xmpp-server3.l.google.com.
_xmpp-server._tcp.gmail.com has SRV record 20 0 5269 xmpp-server4.l.google.com.
% host -t a xmpp-server.l.google.com.
xmpp-server.l.google.com has address 64.233.167.125

というわけで通信できない原因が分かったので、 あとは GCD の jabber サーバに SRV レコードを参照させればいいだけですが、 幸い現在使っている jabberd2 サーバは SRV レコードを参照する機能を持っていました。 なので設定ファイル resolver.xml に次の行を追加するだけです:

  <lookup>
    <srv>_xmpp-server._tcp</srv>
    <srv>_jabber._tcp</srv>
  </lookup>

また、SRV レコードを参照する jabber サーバ&クライアントのために、 ネームサーバに SRV レコードを登録しておいたほうがいいでしょう。 GCD ではネームサーバとして djbdns を使っているので、 次の行を tinydns のレコードファイルに追加します:

:_jabber._tcp.jabber.gcd.org:33:\000\012\000\000\024\225\006jabber\003gcd\003org\000
:_xmpp-server._tcp.jabber.gcd.org:33:\000\012\000\000\024\225\006jabber\003gcd\003org\000
:_xmpp-client._tcp.jabber.gcd.org:33:\000\012\000\000\024\146\006jabber\003gcd\003org\000

以上の修正を行なった上で、 GCD と Google Talk それぞれに jabber クライアントでログインして、 チャットしてみると、あっさりつながりました。 続いて同様の修正を jabber.jp に対しても行ないました。

というわけで、約5ヶ月の間ご迷惑をおかけしましたが、 jabber.jp と Google Talk は、 ようやく本日より相互接続できるようになりました。

Filed under: システム構築・運用 — hiroaki_sengoku @ 13:18
2006年6月21日

時間ができたら勉強したい、というのは禁句

好きなこと = 他の人に勝てる分野

負けることを恐れるあまり、勝つことに価値を見いだせなくなってしまった人たち」に 頂いたコメントを見ていて、 あらためて日本語の難しさを痛感する (^^;)。

「勝てることが好き」 と 「勝てるから好き」 と 「勝つことが好き」

文字ヅラはとても似ているが意味はだいぶ違う。 私が書いたのは「勝てることが好き」だったのだが...
「勝つ」こと自体が好きと、「勝てること」が好きでは、 もちろん全然意味が違うし、 どんな分野であれ最初から「勝てる」ことなどないのだから、 勝てる「から」好き、というのもちょっと違う。

「好きだから注力する」⇒「注力するからより上達する」⇒ 「上達を実感するから、より好きになる」 という正のフィードバックによって、 しだいに勝つことができるようになるのである。 「勝つ」は結果であって、理由ではない。 つまり「勝てるから好き」ではない。 もっとも、「勝ちたいから注力しているうちに好きになる」ということは あるが。

やりたいことを見つけるにはどうすべきか?

Mimiteru さまのコメントから引用:

業務も職種も世の中にはたくさんあります。 やりたいことがわからない人は、 本当にプログラマがやりたいのかさえも漠然とした意識を持たないのかもしれません。

その通りだろう。 何がやりたいのか見つけるには、 好きでなくても手当たり次第に挑戦してみることも必要である。 何事も始めてみなければ始まらない。

ところが、挑戦してみることを勧めると、 「時間ができたら勉強したい」と答える人のなんと多いことか。 率直に言って、こう答えた時点で好きになれる可能性はゼロである。 何事も始めてからの方が困難なことが多い。 まして勝てるようなレベルを目指すなら、 好きでなければやってられないことも多いだろう。

世の中は、何をするにしても道半ばで、進むのを止めてしまえと 囁く誘惑に満ち満ちている。 「時間がない」ことを「いいわけ」にして始めないようなら、 仮に始めたとしても、困難にぶち当った途端、 山のような「いいわけ」を持ち出して自己を正当化し、 進むのを止めてしまうだろう。

好きなことがあるなら、時間なぞなくても始めてしまうだろうから、 こんな「いいわけ」は言わないだろう。 好きなことがないなら、そして何かやりたいことを見つけたいと本当に思うのなら、 「いいわけ」を口にしたくなっても思い止まるべきだ。 最初から「いいわけ」を口にしていて好きになれるはずがない。

勉強を始める最適な日は、今日という日をおいて他にない。

Filed under: 技術者の成長 — hiroaki_sengoku @ 06:30
2006年6月20日

コンピュータ科学における体系的な知識 hatena_b

断片的な知識と体系的な知識」にトラックバックを頂きました。 長久さま曰く:

体系的な知識を学ぶことはある程度可能です。 但し、その分野が十分に研究されていて、体系化されているならば、 という条件が付きます。体系化は、学問化と言っても良いでしょう。 この場合、本当に良くできた教科書を読むことで、 体系的な知識を学ぶことができます。
しかし、多くの分野では、体系化まで行ってません。 コンピュータ科学においても、体系化まで進んでいる分野は、一握りです。

「体系」を辞書で引くと、 「一定の原理で組織された知識の統一的全体」(広辞苑) とあります。 私は「統一的全体」として、 かなり広範囲の学問分野を想定していたのですが、 長久さまは「コンピュータ科学においても、体系化まで進んでいる分野は、 一握りです」と 表現されていることから、 もっと狭い個々の技術分野について考えられているのでしょう。 技術分野がどんどん細分化されていく昨今、 長久さまのように、 個々の技術分野の「体系」をイメージされるかたのほうが 多数派なのかも知れませんね。

私がイメージする「体系的知識」とは、 コンピュータ科学でいえば、 例えば「オートマトン理論」のような学問体系のことです。 現在のコンピュータは全てオートマトンですから、 コンピュータ科学全体が一つの体系と言ってしまってもいいかも知れません。 この意味でコンピュータ科学は、かなり体系化されています。 コンピュータ科学という「体系」の視点から見れば、 その中の個々の技術分野の「体系」は、 他の技術分野と相互に関連づけられていない限り 「断片的知識」と言いきってしまえるかも知れません。

「コンピュータ科学 体系」で Google 検索してみると、次の本が見つかりました:

図解雑学 コンピュータ科学の基礎 河村 一樹 (著)

内容
ほとんどの情報処理試験に出題され、 もっとも難しいジャンルとされる「コンピュータ科学基礎」について 図版を豊富に使って丁寧に解説。 コンピュータ科学がいかに体系化され、 いかに研究が進んでいるかを実感できる本。

目次
1 コンピュータサイエンスと符号化理論の基礎
2 論理学の基礎
3 集合論の基礎
4 形式言語理論の基礎
5 オートマトン理論の基礎
6 グラフ理論の基礎
7 プログラミング論の基礎

検索で見つけただけの本なので内容がどうなってるのか分かりませんが(^^;)、
この目次は、コンピュータ科学の体系を俯瞰するのに丁度いいと感じました。

オートマトン理論の中には、 チューリングマシンや計算量の理論などが含まれてくるでしょう。 非決定性チューリングマシンが多項式時間で解くことができる問題のクラス NPや、 オラクル付チューリングマシンが解くことができる問題のクラス階層は、 コンピュータ科学の体系の中でも最も重要な概念の一つと言っても いいかもしれません。

# オラクルといっても DBMS でもなければ、マトリックスの母でもありません ;-p

また、グラフ理論に関連する分野として、組み合わせ理論や探索などがあります。 遺伝的アルゴリズム(GA)は、確率的探索の中の一分野に過ぎません。 GA を単に、交叉・突然変異・自然淘汰からなる探索アルゴリズムとして 理解してしまうと、 本質を見失ってしまうのではないでしょうか。

プログラミング論には、 近年急速に発展しつつあるソフトウェア工学全体が含まれてきます。 秒進分歩といってもいいくらい新しい概念が次々と提案される分野ですが、 本質さえきちんと押えておけば、 数年で廃れる流行に振り回されずに済むのもまた事実です。

同ページで長久さま曰く:

「これ読めば、探索を体系的に学べます」というオチがきたら良かったと思います。 この終わり方だと、生殺しっぽいので。 でも、探索を体系的に記した本って、タブンないと思うんですよね。 捉えるレベルがメタ過ぎて、抽象的になっちゃうと思うので。

まずはコンピュータ科学全体を俯瞰し、 「論理学」「形式言語理論」「オートマトン理論」 「グラフ理論」「組み合わせ理論」「符号化理論」などの コンピュータ科学を支える重要理論を大ざっぱに把握した上で、 特に興味がある分野(例えば探索)をより突っ込んで勉強する、という方法が いいのではないかと思っています。 重要なのは、最初のうちは枝葉末節にあまり捕らわれないようにすることでしょう。 木を一本一本見ていて森が理解できるようになるほど、 コンピュータ科学という森は小さくありません。 まずは森全体の地図を見て体系を理解しておくことが重要でしょうね。

More...
Filed under: 元CTO の日記,技術者の成長 — hiroaki_sengoku @ 06:37
2006年6月17日

stone 2.3b リリース

stone 2.3b をリリースした。 現時点ではスナップショット扱いであるが、 重大なバグが発見されない限り、 このバージョンを stone 2.3 に代えて正式リリースとする予定。 stone 2.3a からの変更点は以下の通り。

doReadWrite select ループを抜けるバグを修正

stone.c 2.2.2.6 で doReadWrite から doReadWritePair を分離したときに作りこんでしまったバグを修正。

このバグにより、意図せず doReadWrite select ループを抜けてしまい、 パフォーマンスが大幅に低下するケースがあった。 詳しくは SSL_Pending を参照。

アーカイブから stone.1 と stone.1.ja を削除

stone 2.3 と stone 2.3b との仕様の差分を、 マニュアル stone.1 および stone.1.ja に反映できていないので、 とりあえず削除。

現時点での stone の正式マニュアルは、 パッケージ同梱の README.txt および README.en.txt である。

変数名の変更など

関数の仮引数と同じ変数名のローカル変数を使っていた。 stone.c 2.2.2.23 で修正。

Filed under: stone 開発日記 — hiroaki_sengoku @ 22:02
2006年6月14日

負けることを恐れるあまり、勝つことに価値を見いだせなくなってしまった人たち hatena_b

『他の人に勝つ』ということに価値を見いださない人たち」に頂いたコメントから発展して、 /.j 方面でいろいろなコメントを頂いた。 いろんな考え方の人たちと議論することによって 考えが深まるので大変ありがたいことだ。 曰く:

この方は競争に勝つために勝てる分野を選んで それを好きになるという習慣を自分の中に構築して行った結果、 それがあまりにも固定化された「大前提」になってしまって、 そこに至るまでの「自分がなにをしたいのか」について ちゃんと考えることを止めてしまっているのではないかと思います。

どうやら昨今の事件によって「勝つ」という言葉の持つ負のイメージが 大きくなってしまっているようだ。 なにごとにも光と影の面がある。 勝つ人がいれば当然負ける人がいる。 負ける人のことに焦点をあてれば、 勝つことに価値が見いだせなくなるのは当然のことだろう。

では、「勝つ」という代わりに「人より『上手く』やる」と言い換えたらどうだろう? 例えば、「私は普通の人より効率的なコーディングができる」。 私よりコーディングの効率が劣る人は「負け組」だろうか?

もちろん違う。 単にコーディングに向いていないだけなのだ。 自身の適性を早く把握して、 自分に向いていることを見つけ出し、 それを好きになって取り組めば、 おそらくその分野では私より「上手く」やることができるようになるだろう。

「勝ち組」は一割以下だという。 ほとんどの人は「負け組」になってしまうから、 そもそも「勝ち負け」にこだわるのはよくないと、 まるで小学校の徒競走みたいなことを言う人がいる。

しかし、なぜ負けた人がその分野にこだわる必要があるのか? ある分野で負けても、他の分野で見返してやればいいではないか。 みんながそれぞれ自分に一番向いていることをすれば、 「勝ち組」の割合はずっとずっと増えるだろう。

これこそ、それぞれの人の多様な能力を伸ばすことをめざす 「ゆとり教育」の目標であったはずだ。 ところが現状は皆が自身の個性を無視して同じようなことを目指す。

徒競走でビリの子が出るのが問題なのではなく、 みんなを運動会に等しく駆り出すことが問題なのである。 勝ち負けをはっきりさせなければ誰が運動能力に優れ、 誰が向いていないのか曖昧になってしまう。

受験戦争が問題なのではなく、 大学で学ぶ意欲も能力もない子まで大学へ進学させようとするのが問題なのである。 大学で学ぶ意欲も能力もない子でも、 受験テクニックを無理矢理覚え込ませればテストの点は上がるかもしれないが、 そういった子たちが大学に入って何をするというのだろう。

お金儲けが問題なのではなく、 自身の適性を無視し、自分がやりたいことを見失って、 向いていない仕事を嫌々やっていることが問題なのである。 「プログラマ 35歳 定年説」に書いたように、 できるだけ早い段階で勝ち負けをはっきりさせ、 自分に向いていることを見つけるべきなのである。

Filed under: 技術者の成長 — hiroaki_sengoku @ 08:11
2006年6月13日

ロングテール戦略が格差社会を生む: 究極の搾取

仮説: ロングテール戦略が格差社会を生む の検証の一回目 (全七回を予定)。

究極の搾取

剰余価値が生まれて以来、 持つ者が持たざる者を 搾取する、 という構図は変わらない。

産業革命の時代、資産とは生産諸手段だった。

情報革命の今日、資産とは知能である。

頭のよい者が儲け、頭がよくない者は自覚のないままに搾取されている。 搾取と言っても、一人一人の額は微々たるものだから、気付かないのだろう。 たまに、「ボロ儲け」した奴はけしからん、と一部の金持ちが槍玉にあげられるが、 本当の金持ちは目立たないようにしているものだ。 一人一人に対する搾取は極めて少額でも、 情報技術の力によって集めれば莫大な額になる。

かつて「搾取」が持っていた暗いイメージはもはやない。 産業革命時代の搾取と違って、 今日の搾取には悲惨さは微塵もない。 かつての搾取はその悲惨さによって下層階級を固定していたが、 今日の搾取にはその力はない。 したがって産業革命時代と異なり、 今日は搾取それ自体が格差社会を生んでいるわけではない。

その一方で、富を集積する力は従来と変わらず圧倒的である。 しかも、産業革命時代の機械と比べると、 今日のコンピュータおよびネットワークは、 費用対効果が極めて高い。

圧倒的な効率で富を集積する力を持ち、 しかも負の側面をほとんど持たない。
まさに究極の搾取と呼ぶにふさわしいだろう。

Filed under: 自己啓発 — hiroaki_sengoku @ 07:47
2006年6月11日

TCP/IP を使った DNS 問合わせ

DNS問合わせというと、 ネームサーバの UDP/IP の 53番ポートへ問合わせるのが一般的であり、 TCP/IP の 53番ポートはゾーン転送のみに使われることが多い。 しかし RFC (RFC1035 および RFC2136) 上は TCP も、UDP と同様、 通常の問合わせにも利用することができることになっているし、 多くのネームサーバでそのような実装になっている。

手近なネームサーバが利用できない環境 (某ホテルの無線LAN 環境など ;) で、 やむを得ず遠方のネームサーバを利用する際などに、 TCP を使って問合わせをすると、 ポートフォワードすることもできて便利である。

拙著「ネーム・サーバ (前編)」に書いたようにネームサーバには二種類あって、 ここで言うネームサーバは、 「/etc/resolv.conf に登録できるネーム・サーバー」のことである。 つまり、リゾルバから問い合わせがあると, 他のネーム・サーバーに問い合わせて結果を返してくれるタイプである。 一般にはキャッシュ ネーム サーバと呼ばれることが多いようだ。
ちなみにネームサーバには他に、 「答えを知っている問い合わせに対しては答えてくれるけれど, 知らない場合は,どこどこへ聞けと冷たく言い放つタイプ」がある。
また、キャッシュ ネーム サーバの一形態として、 他のキャッシュ ネーム サーバへ問合わせを転送する フォワード専用型キャッシュネームサーバもある。

広く普及しているネームサーバ実装の一つである djbdns には、 UDP 問合わせに失敗したり、 あるいは 512バイト以上の問合わせを行なう際は、 TCP にて問合わせを行なう機能があるが、 最初から TCP しか使わない (キャッシュ) ネームサーバがあると便利だろう。 すなわち、 遠方のネームサーバへ TCP で問合わせを転送する、 フォワード専用型サーバである。

フォワード専用型 キャッシュ ┌→ルート (root) ネームサーバ
リゾルバ──→キャッシュネームサーバ──→ ネームサーバ─┼→ネームサーバ
UDP TCP  ├→ネームサーバ
 └→

といった感じで TCP専用サーバを用いる。 この TCP専用サーバの作り方は簡単で、 djbdns の場合ならば次のようなパッチをあてるだけである。

dns_transmit.c で定義されている dns_transmit_start() 関数の末尾部分で、
    if (len + 16 > 512) return firsttcp(d);
    return firstudp(d);
となっている部分を、
    /* if (len + 16 > 512) */ return firsttcp(d);
    return firstudp(d);
で置き換える。

このようなパッチをあてた dnscache プログラムを、 環境変数 FORWARDONLY をセットした状態で呼び出せば、 「servers/@」に指定したキャッシュネームサーバへ TCP で問合わせを転送する、 フォワード専用型キャッシュネームサーバになる。

Filed under: システム構築・運用 — hiroaki_sengoku @ 08:59
2006年6月8日

ロングテール戦略が格差社会を生む

ふと思いついた仮説: ロングテール戦略が格差社会を生む を検証していこうと思う。

凡人が万馬券ばかり買って競馬場を去る社会」 「格差」 「過ぎたる機会は及ばざるがごとしか」など、
格差社会」というテーマが最近ホットであるようだ。 これらのブログを読んでいて違和感を感じた。
別の視点から「格差」を論ずることができるような気がしている。

論拠は次の 7 つ。

  1. 究極の搾取
  2. 必要は発明の母
  3. 機会均等
  4. 最も貴重な資産
  5. 習慣
  6. ラットレース
  7. 仮想下層社会

これだけで私が何が言いたいか分かってしまった人もいるかもしれないが (^^;)、 今後一つずつ掘り下げてみる予定。 ご意見を頂ければ、より突っ込んだ議論ができるかもしれない。

Filed under: 自己啓発 — hiroaki_sengoku @ 08:44
2006年6月6日

ライブドア ブログのXHTML文法チェック

ふと思い立って、このブログ(livedoor Blog)の XHTML文法チェックを行ってみた。 予想通り、山のような文法エラーが見つかった。(^^;)

片っ端から修正し、ほとんどは駆逐できたのだが、 ユーザ設定できない以下の部分についてはどうにもならない。

修正不可能な文法エラー

ユーザ設定できない部分なので修正できない。

HTMLテンプレートでアイコンのURLを示す変数の値が異常

次のようなHTMLが生成されてしまう:

<div class="powered">
<a href="http://blog.livedoor.com/">
<img src="http://img.blog.livedoor.com/img/usr/cmn/blog_pro.gif
"
width="117" height="28" border="0" alt="livedoor Blog(ブログ)"
title="livedoor Blog(ブログ)" />
</a>
</div>

なぜか、blog_pro.gif のURL の直後に改行コードが入っている。
これは、HTMLテンプレートでは「<$LDBlogLogo$>」となっている部分。

outfooterの部分

HTMLテンプレートで生成した HTML に、 システムが自動的に追加する outfooter に次のような部分がある:

<script type="text/javascript" src="http://parts.blog.livedoor.jp/js/c.js">
</script>
<script language="JavaScript">blog_counter('hiroaki_sengoku')
</script>
<script type="text/javascript" src="http://blog10.analyzer.livedoor.jp/x.js?pid=39952">
</script>
<noscript>
<img src="http://blog10.analyzer.livedoor.jp/img/a.gif?pid=39952">
</noscript>

なぜか二番目の JavaScript だけ 「language="JavaScript"」という属性になっている。 一番目、三番目と同様「type="text/javascript"」にすべきだと思う。

また、img タグが閉じていないのと、alt属性がない。

以上は、HTMLテンプレートで設定可能な範囲外であるので、 対処できない。

修正可能ではあるものの望ましくない文法エラー

上記の問題点のほか、回避手段があるとはいえ、 以下の点も問題だろう。

「ブログ検索」プラグイン

プラグインとして「ブログ検索」を使用すると、 以下のような HTML を生成してしまう:

<form action="http://sf.livedoor.com/search" method="GET" style="padding:0;margin:0px;">
<input type="HIDDEN" name="q" value="allinblog:http://sengoku.blog.klab.org/">
<input type="TEXT" name="q" class="sf">
<input type="SUBMIT" value="検索" class="sfbtn">
</form>

inputタグが閉じていない。 また、「method="GET"」は「method="get"」のほうがよいだろう。

「ブログ検索」プラグインを使わず、 「フリーエリア」プラグインを使って 正しい XHTML を書けば対処可能ではあるが...

改行をそのまま反映

「投稿フォームの設定」で「改行をそのまま反映」を選択すると、 行末に「<br>」が挿入される。 「<br />」でないと XHTML 的には文法エラーになってしまう。

Filed under: その他 — hiroaki_sengoku @ 19:22
« Newer PostsOlder Posts »