雑記帳 2006年 8月第1週

2006/08/01 Tue.

8月初日から涼しくて素晴らしいスタートだ。某銀行員の書いてる「mixi」の日記によると、仙台市内は21度とからしいが。
2年ぶりに経験した梅雨も、今年は邪魔くさいモンじゃなかったな。靴に穴が開いてるから水が滲みるのはアレだったが。

ところで、「- プログラマをお勧めしない10の理由 -」なんてサイトを見つけた。微妙に的確だが、微妙にズレてる気もする。
項目4はいまいちよくわからんな。見下されているが故に、上から言われるままになっているってことを指すんだろうか?
項目8は環境次第といったトコか。基本的に思考能力を酷使する仕事なので、精神面での疲労はかなりのものがあるかと。
項目9はどんなモンだろうか。確かに行き遅れる職業だとは言われているが、それも環境に依存する部分が大きいのでは?
そして項目10には文句を言いたい。これは30歳で脱落した連中の自己弁護及び業界にまつわる迷信の一種だと思う。

全然話が変わるけど、某MMOのゲームサーバーは非常に重い。反応速度が100msを超えることも頻繁にある。
利用前にサーバーの負荷状況がわかればいいのだが、pingを打ってみても遮断されてしまい、反応速度がわからない。
100msなんて0.1秒だし、全然気にすることは無いだろと思うかもしれないけれど、サーバーは軽ければ軽いほど良い。

C:\>ping xxx.xxx.x.x

Pinging xxx.xxx.x.x with 32 bytes of data:

Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for xxx.xxx.x.x:
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),

IPアドレスは隠すけど、こんな感じでpingを打っても無反応なのです。pingを遮断されると、反応速度は調べられないのか?
もちろん納得いく自分ではありません。SocketTime::HiResあたりを使えば、Perlを使って何とかできないものだろうか。

use strict;
use Socket;
use Time::HiRes qw (gettimeofday tv_interval);
for (my $i = 0; $i < 4; $i++) {
    printf ("%d[ms]\n", getElapsedTimeOfConnecting ("127.0.0.1", 80) * 1000);
    sleep (1);
}

sub getElapsedTimeOfConnecting {
    my ($server, $port) = @_;
    socket (SOCKET, PF_INET, SOCK_STREAM, 0);
    my $addr = inet_aton ($server);
    my $sock_addr = pack_sockaddr_in ($port, $addr);
    my $time = [gettimeofday];
    connect (SOCKET, $sock_addr);
    my $ret_time = tv_interval ($time);
    close (SOCKET);
    return $ret_time;
}
C:\>perl SocketConnection.pl
0[ms]
0[ms]
0[ms]
0[ms]

pingの意味とはズレるかもしれんけど、反応速度を調べるなら十分。iptablesでpingを遮断されても突破でき……るのか?
ちなみに対象がLocalhostなので0.000秒になってるけど、外部サーバーで試せば0.001秒とか0.003秒って出てくると思う。
とにかく、pingを遮断してても反応速度を測定できたってだけの話です。ちょっとしたメモ代わりみたいなモンってことで。

2006/08/02 Wed.

昨日のソースはあれこれ調べながら書いたから、その詳細をどこかに残しておかないと自分でも理解できなくなりそうだ。

  • socket(SOCKET, PF_INET, SOCK_STREAM, 0)
    • ソケット(プロセスと外界をつなぐインターフェース)を生成する。
      PF_INET」はインターネットに接続、「SOCK_STREAM」はTCP接続を指し、Socketモジュールの定数である。
      例えば「PF_LOCAL」と記述すればUNIXドメインソケットを生成し、「SOCK_DGRAM」と記述すればUDP接続を指す。
  • inet_aton ($server)
    • ホスト名をIPアドレスの4バイトの構造体に変換する。
      例えば、「$server = inet_aton ("localhost");」と記述した場合はIPアドレスは「127.0.0.1」となり、
      各数値を変換した「0x7F」「0x00」「0x00」「0x01」という構造体が入る。
  • pack_sockaddr_in ($port, $addr)
    • ポート番号とIPアドレスをまとめた構造体を生成する。connect時に使用。
  • [gettimeofday]
    • 配列コンテキストではエポックからの秒とマイクロ秒2つの要素の配列を返す。
      $time = gettimeofday();」のようなスカラー・コンテキストでは、秒を浮動小数点数で返す。
  • tv_interval ($time)
    • 2つの時刻の時間を浮動小数点の秒数を返す。
      2つの時刻はgettimeofday()で返されたものでなければならない。
      2番目の引数が省略されると、現在の時刻が使われる。

未踏の分野に手をつけると学ぶべきことが多いな。Time::HiResはともかく、Socketは覚えておいた方が良さそう。
Time::HiResgettimeofdayの使い方がどうにもわかりにくかったが、とりあえず以下の結果をメモ代わりに残してみる。

C:\>perl -e "use Time::HiRes qw (gettimeofday); @time = gettimeofday; print \"@time\n\";"
1154489544 359375

C:\>perl -e "use Time::HiRes qw (gettimeofday); $time = gettimeofday; print \"$time\n\";"
1154489732.28125

C:\>perl -e "use Time::HiRes qw (gettimeofday); $time = [gettimeofday]; print \"$time\n\";"
ARRAY(0x27512c)

Socket関連では「ネットワークプログラミングの基礎知識」というサイトがあるが、初心者の自分にもかなり役に立った。

use strict;
use Socket;
my $host = "localhost";
my $port = getservbyname ("http", "tcp");
my $iaddr = inet_aton ($host);
my $sock_addr = pack_sockaddr_in ($port, $iaddr);
socket (SOCKET, PF_INET, SOCK_STREAM, 0);
connect (SOCKET, $sock_addr);
select (SOCKET);
$| = 1;
select (STDOUT);
print SOCKET "GET /index.html HTTP/1.0\n\n";
while (<SOCKET>) {
    print $_;
}

とりあえず超簡単なサンプルって感じで書いてみた。途中に「$| = 1;」ってのがあるけど、ようやくこの意味わかった。
一応バッファリング関係だってのは知ってたけど、この部分に関しての詳細な説明を今まで見たことなかったんだよね。
某とほほの掲示板のログに「出力をバッファリングしないとは?」ってのがある。読みにくいけど、一応理解できたからよし。

で、Perl関係で色々と巡っていると「- Perlプログラマのレベル10 - Perlプログラミング救命病棟より」なんてのを発見。
ここを見る限りでは、先日までレベル4だった自分は何とかレベル5になったトコか。今となっては「use strict;」は手放せん。
ってか、そもそも自分が「Programming」で配布してるのはグローバル変数だらけの恐怖のソースコードなんだよな。
開発してた当時も変数があれこれ入り混じってメンドいとかって思ってたけど、今読み直してみるともはや理解できん。
しかしながら世の中は不思議なもので、「Pocket詳解 Perl/CGI辞典」という2006年5月5日初版の本にこんな記述が。

[参考] strictプラグマは厳密すぎるため、通常のプログラミングではあまり使用しません。

ちょ、おま、どういうこっちゃ!趣味でPerlをやっている身としては、今後はstrict対応していきたいと思っていたのに。
この件では「ここ」が色々と考察されているようです。なるほど、趣味でやるには制約がキツすぎるって意味合いですか。
でも、グローバル変数が山盛りなソースコードは触りたくないし、可能であれば趣味の範囲でもstrictした方がいいよな。
「use warnings;」に関してはどうしたモンだろうか。これが実装されたのってPerl5.6.0以降だよな。使うべきなのか?

そうそう、昨日に職場のマシンのPerlを5.8.8に入れ替えました。自宅のマシンのは5.6.1だし、近いうちに入れ替えだな。
Javaとかだったらバージョン違いでどんな機能が追加されたとかは少しはわかるんだけど、Perlに関してはサッパリだ。

2006/08/03 Thu.

自分はJava初心者です。どれほど初心者かというと、JDBCでclasses12.zipとclasses111.zipの違いがわからない程度。
両方クラスローダーだかクラスパスに入れとけばいいとか思ってたんだけど、やっぱり不要なゴミは入れたくはない。
しょうがないので、「JDBC開発者ガイドおよびリファレンス」なんてPDFに目を通してみる。疑問は変なトコで解消するもんだ。

ドライバ実装はそれぞれ、独自のJDBCクラスZIPファイルを使用します。
JDK1.4、1.3.xおよび1.2.xバージョンの場合はclasses12.zip、JDK1.1.xバージョンの場合はclasses111.zipです。

両方の圧縮ファイルを解凍して「\oracle\jdbc\driver」を参照しても、クラスファイルが同じだったから違いがわからんかった。
厳密に言えば、存在するクラスファイルの名前と数だけが同じなだけで、普通にバイナリ差分があったワケだけど。
さすがにJDK1.1.xみたいなレガシーは使わないだろうし、今後にJDBCを使うのであればclasses12.zipがあればいいワケか。
上記PDFを配布する「Oracle Technology Network (OTN) Japan」、面白い記事が揃ってるな。近い内に読みまくろう。

2006/08/04 Fri.

歳を食った。7月25日のニュースで日本人の平均寿命が発表されたが、男78.53年のうちの33.1%を過ぎたワケだな。
どうでもいいんだけど、8月4日という日は何か特別な日だったりしないのかと思い、「8月4日 - Wikipedia -」を見てみた。
面白い出来事があるワケでもなく、今日が誕生日の人に有名どころも無し。鞄職人のLouis Vuittonは今日が誕生日だが。

今日はさっさと定時で上がって、埼玉県庁勤務の某K岡の召喚に成功したので、青梅特快で新宿へ向かいます。
どこで飲もうかという話になり、靖国通り沿いのトコで胡散臭い店があったので行こうとするも、見事に満席だった。
見るからに昭和の香りが漂うという、いかにも自分とK岡に来てくれと言わんばかりの店だったのだが。また後日だな。
比較的新しい店っぽかったな。「銀座カンカン」というトコでした。ま、今回はスルーってことで。Y崎先生も連れてきたいな。
結局「Hot Pepper」で見つけた胡散臭さ全開の「食彩工房 戦艦大和」とかいうトコに特攻してみることになった。地雷覚悟。
店の前まで行くと、客引きのおにーさんが。「金曜夜なのに人が入らないんですよねー」だとか。店員自ら地雷宣言か?
少し悩んだものの、とりあえず飲み放題(1,500円じゃなくて何故か1,000円になってた)にして店内へ。で、驚愕の光景が。

超ガラガラ!ってか、俺ら以外に客が一組しかいねぇ!覚悟はしていたものの、地雷の予感を確定させられると凹む。
お通しがポップコーンとかいう時点でお察し下さい。飲み物と食べ物はそれなりに普通だった気はしないこともない。
で、気になったのは「何故に店名に戦艦大和?」という点。戦艦をネタにしたオリジナルカクテルとかがあるワケでもない。
どうでもいいけど、戦艦って英語では「Battleship」らしいんだけど、駆逐艦ってのは「Destroyer」というらしい。仰々しいな。
しばらくすると、K岡の携帯が鳴る。どこぞのお偉いさんのS保様からで、京都に出張行っててその帰りだとか言う。
実は今日は珍しく自分が三人を誘ってみたのだが、反応したのはK岡のみ。で、S保の電話先は何で俺じゃなくK岡かい。
どうやら東京にいるらしいから、とりあえず歌舞伎町のこの店まで来いと言っておく。40分くらい経ってS保が登場。
……どう見ても既に酔っ払いだ。どうやら出張帰りの新幹線で上司に付き合ってビール飲んだらしい。公務員必死です。

S保が来たのが飲み放題の時間が終わった頃だったので、次の店へ移動。S保がどっか連れてってくれるらしいが。
コマ劇の前あたりから靖国通りまで出て、新宿区役所をも通り過ぎる。随分遠いな。着いた店が「茶茶花」という和食の店。
地図見てもらえばわかると思うけど、何だってこんなわかりにくい場所の店を知ってるんだ。住所が歌舞伎町1-1-1って。
店の雰囲気は前述のURL参照で。写真も撮ってみたけど、所詮は携帯だし暗かったしでイマイチな写真になってしまった。
途中から妙な流れになり、俺とS保がそれぞれ後輩の某Kと某Mを呼び出すという話になったが、とりあえず撤回で合意。

23時半まで食って解散。金曜夜の終電間近の下り急行は、久々に体験する超満員。懐かしいが味わいたくない感覚。
千歳烏山で痴漢だかケンカだか(客同士のトラブルとしかアナウンスされん)で微妙に遅れるも、0時半に多摩セン着。
土曜日は免許の更新にでも行けたらラッキーだとか思ってたんだが、前日がこんな状況じゃ間違いなく行かないだろうな。
来週はどっかの横浜市民がまた言い寄ってきそうだが、今日来なかったってことで、免許の更新は来週に充てておこう。

2006/08/05 Sat.

さて、「Simple Scheduler」なんてのを公開してみる。自分は手帳持たないから、スケジュールはオンラインで管理したい。
今の出向先では年末だか年始あたりに手帳をもらえるんだけど、いかんせん「書き込む」という作業がメンドいのよね。
ちなみに、スケジューラーを作ってみようと思い立ったのが1月6日だったらしい。かなり放置状態にしてたんだな。
ある程度作ってあった手元のソースに何か機能を付け加えてから配布しようと思ってたんだけど、あまり思いつかない。
とりあえず、カレンダー画面から詳細画面を開かないでも、その日のスケジュールの有無を確認できるようにはした。
使ってみればわかると思うだろうけど、あまりまともなスケジューラーじゃないな。ある意味では自分専用みたいだ。

そうそう、Perlではリファレンスを使って二次元配列を表現するけど、実は自分はリファレンスとかさっぱりわかりません。

use strict;
my @array1 = ();
for (my $i = 1; $i <= 9; $i++) {
    my @array2 = ();
    for (my $j = 1; $j <= 9; $j++) {
        push (@array2, $i * $j);
    }
    push (@array1, \@array2);
}
for (my $i = 0; $i < 9; $i++) {
    print join ("|", map {$_ = sprintf ("%02d", $_)} @{$array1[$i]}) . "\n";
}
C:\>perl test.pl
01|02|03|04|05|06|07|08|09
02|04|06|08|10|12|14|16|18
03|06|09|12|15|18|21|24|27
04|08|12|16|20|24|28|32|36
05|10|15|20|25|30|35|40|45
06|12|18|24|30|36|42|48|54
07|14|21|28|35|42|49|56|63
08|16|24|32|40|48|56|64|72
09|18|27|36|45|54|63|72|81

勉強がてらに適当な例で書いてみた。リファレンスは簡単だからいいけど、デリファレンスがメンドくさそうだな。

use strict;
my $value = 'value';
print '$value=' . $value . "\n";
my $value_reference = \$value;
print '$value_reference=' . $value_reference . "\n";
my $value_new = ${$value_reference};
print '$value_new=' . $value_new . "\n";
my @array1 = qw (a b c);
my @array2 = qw (1 2 3);
my @array3 = (\@array1, \@array2);
for (my $i = 0; $i < scalar (@array3); $i++) {
    for (my $j = 0; $j < scalar (@{$array3[$i]}); $j++) {
        print ${@{$array3[$i]}}[$j];
    }
    print "\n";
}
C:\>perl test.pl
$value=value
$value_reference=SCALAR(0x274f84)
$value_new=value
abc
123

わかったような、わからんような。Javaっぽく言うと、デリファレンスした時にキャストしないといけないって感じか?

use strict;
my @array1;
for (my $i = 0; $i < 3; $i++) {
    for (my $j = 0; $j < 3; $j++) {
        $array1[$i][$j] = $i * $j;
    }
}
print join (" ", @array1);
C:\>perl test.pl
ARRAY(0x274f90) ARRAY(0x274dec) ARRAY(0x1830e2c)

ってか、二次元配列を使うのにリファレンスを使わないでやる方法って無いんだろうか。これ覚えないといけないのかぁ。
配列の連結とかは「@array = (qw (1 2 3), qw (4 5 6));」みたいに超簡単なクセに、何で二次元配列はメンドいのかね。
もちろん内部ではメモリの参照先を格納してるってのはわかってるけどさ。うーむ、リファレンス使って何か作るか?