カウンタが(flockで?)壊れない様にするには?

[上に] [前に] [次に]
Pachell [E-Mail] 1999/10/30(土) 04:56:18
いつもお世話になっています.Pachellといいます.

早速質問なのですが、カウンタがたまに壊れてしまいます.

それを回避するのにカウンタファイルを、
 flockすると思うのですが、
 (WWW入門を見ても)やり方が分かりませんでした.(-_-;

環境は、テレウェイです.
 #来年はNEWEBに変更されますが

ご教授よろしくお願いします.

以下、現在使っているCGIです.
 #Web裏技にあったのを元にしています.

▼▼▼ここから

#!/usr/sbin/perl
# ↑このパスはあなたの環境に合わせて設定すること

# HTMLのファイル名を指定する
# "./main.html"
  $html = "./main.html";

# アクセスカウント数を入れるファイルを指定する
# 最初はあらかじめ「0」を必ず入れておくこと
# HTMLにはカウンタ表示する場所に以下の文字列を書いておくこと
#
#   このページには<!--count-->のアクセスがありました。

  $count_file = "index.count";


# HTMLを読み込んで配列に代入
  open(IN,"$html") || die "error\n";
  @lines = <IN>;
  close(IN);

# 今までのカウンタ数を読み込んで変数に代入
  open(DATA,"$count_file") || die "error\n";
  while(<DATA>){ $count = $_; }
  close(DATA);

# 更新時間取得
($mtime) = (stat($html))[9];
($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($mtime);
$mon++;
@week = ("日","月","火","水","木","金","土");
$wday = $week[$wday];
$year = sprintf("%.2d",$year);
$mon = sprintf("%.2d",$mon);
$mday = sprintf("%.2d",$mday);
$hour = sprintf("%.2d",$hour);
$min = sprintf("%.2d",$min);
$sec = sprintf("%.2d",$sec);
$MyStr="’$year.$mon/$mday ($wday) $hour:$min";

# WWWに出力
  print "Content-type: text/html\n\n";
  foreach $line (@lines) {
    $line =~ s/<!--count-->/$count/g; # アクセスカウント数を入れ込む
    $line =~ s/<!--LastMod-->/$MyStr/g; # 更新時間を入れ込む
    print "$line";
  }

# アクセスカウント処理
  $count++;
  open(OUT,">$count_file") || die "error\n";
  print OUT "$count";
  close(OUT);

▲▲▲ここまで

1999/10/30(土) 05:14:40
関係無い所は、はしょってflock使うなら

open(DATA,"$count_file") || die "error\n";
seek(DATA,0,0);
while(<DATA>){ $count = $_; }
close(DATA);
$count++;
open(OUT,"> $count_file") || die "error\n";
flock(OUT,2);
seek(OUT,0,0);
print OUT "$count";
flock(OUT,8);
close(OUT);

でどうかな?
8は要るんだろうか?

1999/10/30(土) 05:18:51
seekも要らないか

ジェンウェイ大佐 1999/10/30(土) 09:46:31
flockを使おうとシムリンクによるロックを使おうとファイルを上書きすると
アクセス頻度によってはカウンターが飛ぶので、私流に改造すると以下の様な
プログラムになりますです。

カウンターファイルにはアクセスのたびに改行記号のみを追記モードで入れて
カウント数を=ファイルサイズとしてやります。これなら書き込み時にファイルを
ゼロクリアしないのでまずログ飛びは起きないです。

アクセスのたびにカウントファイルが大きくなっていくという点がありますが
これはアクセス数が大きくなってきた時に、以下のスクリプトの初期値の項目を
いじってカウントファイルを0バイトにすればOKです。

------------------------------------------------------------------------

#!/usr//local/bin/perl5
# ↑このパスはあなたの環境に合わせて設定すること

# HTMLのファイル名を指定する
# "./index.html"
$html = "./index.html";

# アクセスカウント数を入れるファイルを指定する
# 最初はあらかじめ「0」を必ず入れておくこと
# HTMLにはカウンタ表示する場所に以下の文字列を書いておくこと
#
# このページには<!--count-->のアクセスがありました。

$count_file = "index.count";


# HTMLを読み込んで配列に代入
open(IN,"$html") || die "error\n";
@lines = <IN>;
close(IN);

# 今までのカウンタ数を読み込んで変数に代入
# open(DATA,"$count_file") || die "error\n";
# while(<DATA>){ $count = $_; }
# close(DATA);

$count = -s "$count_file"; #←変更点その1(上三行はコメントアウト)
$count = $count + 0; #←変更点その2(カウントの初期値を入れる。カウント数が大きくなった時の対策)

# 更新時間取得
($mtime) = (stat($html))[9];
($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($mtime);
$mon++;
@week = ("日","月","火","水","木","金","土");
$wday = $week[$wday];
$year = sprintf("%.2d",$year);
$mon = sprintf("%.2d",$mon);
$mday = sprintf("%.2d",$mday);
$hour = sprintf("%.2d",$hour);
$min = sprintf("%.2d",$min);
$sec = sprintf("%.2d",$sec);
$MyStr="’$year.$mon/$mday ($wday) $hour:$min";

# WWWに出力
print "Content-type: text/html\n\n";
foreach $line (@lines) {
$line =~ s/<!--count-->/$count/g; # アクセスカウント数を入れ込む
$line =~ s/<!--LastMod-->/$MyStr/g; # 更新時間を入れ込む
print "$line";
}

# アクセスカウント処理
$count++;
open(OUT,">>$count_file") || die "error\n"; #←変更点その3(>$count_fileを>>$count_file)
print OUT "\n";
close(OUT);

Pachell [E-Mail] [HomePage] 1999/11/01(月) 09:28:25
Pachellです.
レスありがとうございます.

猫さんのレスでテレウェイで使いましたが、
 サーバーエラー(バッドリクエスト)が出てしまいました.
 テレウェイではflock使えないのかなぁ?

それで、ジェンウェイ大佐さんのレスで行けば上手くいきました.

ただ、わたしは、ローカルでAN httpd を使っているのですが、
 そちらではカウントが2つずつ増えました.
(AN httpd の方でも質問しています.)
もし回避策をご存知の方がいらしたら、
 アドバイスお願いします.

ジェンウェイ大佐 1999/11/01(月) 11:25:39
# アクセスカウント処理
$count++;
open(OUT,">>$count_file") || die "error\n"; #←変更点その3(>$count_fileを>>$count_file)
print OUT "\n";
close(OUT);

スクリプトの以上の部位で

$count++;
の行は改造時の消し忘れです。消しちゃって下さい。

そして、

print OUT "\n";



print OUT "1";

とすればAN-WEBサーバでも一ずつカウントします。
(でも何故なんでしょうねぇ??)
要は一バイトづつ追記するだけなので改行でも半角英数でも何でもいいわけです・・・(苦笑)

バーチャルヒューマン [E-Mail] [HomePage] 1999/11/01(月) 12:50:14
>ただ、わたしは、ローカルでAN httpd を使っているのですが、
>そちらではカウントが2つずつ増えました.

>とすればAN-WEBサーバでも一ずつカウントします。
>でも何故なんでしょうねぇ??)

AN HTTPd ということは、OSには、Windowsですね。Windowsで、"\n" をファイル
に書き込むと、"\r\n"/(16進法では、0x0a,0x0d) に展開されます。

=====
ファイルの読み込み&書き出しで、OPEN/CLOSE を2回やるのは
不要です。
open(DATA,"+<$count_file");
とすれば、読み書きが同時にできます。ただし、読んだら
ファイルのシークポイントが動くので、書き出すときには注意を

>猫さんのサンプルを以下のように >> 猫さん引用させていただきました。
open(DATA,"+<$count_file") || die "error\n";
flock(DATA,2);
$count = <DATA>;
$count++;
seek(DATA,0,0);
print DATA "$count";
flock(DATA,8);   #<-- なくても、close()するとロックははずれる用です。(でもあったほうがよいでしょう!)
close(DATA);

※よかったら、<a href="http://www2.freeweb.ne.jp/~atushi_o/" target="_blank">自分とこのHP</a>にCGI用のライブラリあるのでお使いください。

バーチャルヒューマン [E-Mail] [HomePage] 1999/11/01(月) 12:54:58
つっこまれるまえに、自己レスで修正
>に書き込むと、"\r\n"/(16進法では、0x0a,0x0d) に展開されます。
"\r\n"/(16進法では、0x0d,0x0a)

ジェンウェイ大佐 1999/11/01(月) 13:39:59
なるほど、\nだけを出力しても窓OSだと\rを勝手に書き出すんですね。
なんかそのような気がしてはいましたが・・・

ところでロック外しの flock(DATA,8); は新しいバージョンのPERLだったら大丈夫だったと思いますけど
perl4辺りので使うとflock(8)→closeの間にわずかなスキが出来るという話を聞いたことがあるような・・・勘違いだったらすんませんです。

バーチャルヒューマン [E-Mail] [HomePage] 1999/11/01(月) 13:49:04
自己レスで修正しようと思って...先にご指摘されてしましました。(^_^;

>ところでロック外しの flock(DATA,8); は新しいバージョンのPERLだったら大丈夫だったと思いますけど
『とほほのWWW入門−perl−まめ知識−flock()・・・』にこの辺の詳しいところが載っていました。
そー! ご指摘の通り
>flock(DATA,8); #<-- なくても、close()するとロックははずれる用です。(でもあったほうがよいでしょう!)
↑↑↑
つけてはだめですね。
どおしてもつけたいとすると、ロック解放の前に、ファイルのバッファをflushしておけばいいかも。
※ロック系のfunction って、対でないと気持ち悪いと思うのは私だけでしょうか...(^_^;

ふじ 1999/11/01(月) 14:12:33
>\nだけを出力しても窓OSだと\rを勝手に書き出すんですね。

ちょっと補足。
Windows版の Perl で、「テキストモード」でファイルを書き出す
(読み出す)時に、 \r\n <-> \n の変換が行われます。
#OSがやっているのではナイ。Perl がやってる。

Windowsでも、
binmode OUT;
として、バイナリモードにすれば、\r\n <-> \n の変換は行われなくなります。

バーチャルヒューマン 1999/11/01(月) 15:30:05
本件のQ&A から逸脱してすみません。また、このラウンジの趣旨からも
はずたかも?

>#OSがやっているのではナイ。Perl がやってる。
多分、"\n"<->"\r\n"の変換はOS依存で、OSのファイル制御ブロックで
行われていると思いました。ちなみに、Macでは、改行コード="\r"
だそうで。

例えば、C言語を用いて、fprintf(fp,"...\n"); とした場合にも
同様で、"\n"の解釈は、そのファイルのopen モード(text/binary)で
決定されます。コンパイラは、OS非依存で、記述コードを忠実に展開
するはずです。
※念のためでした。。

Pachell [E-Mail] [HomePage] 1999/11/02(火) 16:24:25
[[解決]]
いろいろレス、ありがとうございます.

結局、flockを使わず、1バイト文字追加でいってます.
 #flockはAn httpdだとwindowsはムリと表示された...

何かありましたら、またよろしくお願いします.

[上に] [前に] [次に]