Perl進程間通訊前幾天做了一個比較簡單的東西,但感覺比較意思就在這裡記下來。大概的需求是這樣的:有一個程序在會產生一些警告信息並保存在/var/log/alert中的。如果有新的警告信息時就要在服務器上發出警告的聲音,但啟動是通過web界面的而不是在命令行。
剛開始想到步驟是這樣的:
1、 因為是要在後台運行,肯定是fork一個子進程,父進程退出而不會使web程序阻塞在此,
2、 然後再fork一個子進程,父進程負責監聽日志文件的更新。子進程負責調用聲音程序。兩者之者用管道通訊。
3、 要實時監控日志文件的更新,因為不想搞太復雜就用管道的方式:open(LOG,"tail -n 2 -f /var/log/alert| ") ||die "Unable to open log file $!\n";這樣就可以簡單的得到文件的實時更新
4、 要考慮到退出,所以需要一個文件保存進程ID。
這樣實現的代碼很簡單:
my $pidfile ="/tmp/alertsounds.pid";
sub StartAlertSounds{
my $pid;
if ($pid = fork()) {
return;
} elsif (defined $pid) {
system("echo pid=$ > $pidfile'");#保存進程ID
&RunAlertSounds();
}
}else {
die "Can't fork: $!\n";
}
}
sub RunAlertSounds{
my $pid;
pipe(README, WRITEME);
if ($pid = fork()) { #父進程
close(README);
open(LOG,"tail -n 2 -f /var/log/alert| ") ||die "Unable to open log file $!\n";
while (<LOG>) {
print WRITEME "Sounds\n";
}
close(LOG );
close(WRITEME);
}elsif (defined $pid) { #子進程
close(WRITEME);
while(<README>){
system("/usr/bin/sounds/AlertSounds >/dev/null 2>&1");
}
close(README);
}else {
die "Can't fork: $!\n";
}
}
但測試一下就發現了不少問題:
1、 退出時open(LOG,"tail -n 2 -f /var/log/snort/alert| ")所產生的子進程不會一起退出。
2、 當短時間內(比如1秒)有多條信息過來時,我們希望只產生一條警告聲音,但現在會連續響多條。
3、 有時父進程往管道寫數據時子進程不一定能馬上收到;
分析一下就有下面的解決方法:
1、 使父進程成為進程組的頭領進程,然後在父進程退出前給進程組發送退出信號。
2、 使用鎖機制,父進程寫數據前鎖定。等子進程調用聲音程序完成後再解鎖。在解鎖前如果父進程有監聽到新的警告就忽略。簡單的一點的鎖機制就用一個文件:父進程創建一個空文件表示已經上鎖,子進程刪除這個文件表示解鎖
3、 這個是因為緩存問題,把管道的緩存設置好就行了。
修改後的代碼如下:
my $pidfile ="/tmp/alertsounds.pid";
my $lockfilename="/tmp/sounds.lock";
sub StartAlertSounds{
my $pid;
if ($pid = fork()) {
return;
} elsif (defined $pid) {
setpgrp(0,0);#當前進程成為進程組的頭領
$SIG{INT} = \&catch_zap; # INT信號處理
$SIG{QUIT} = \&catch_zap; # QUIT信號處理
system("echo $ > $pidfile'");#保存進程ID
&RunAlertSounds();
}
}else {
die "Can't fork: $!\n";
}
}
sub RunAlertSounds{
my $pid;
system("rm -f $lockfilename");
pipe(README, WRITEME);
if ($pid = fork()) { #父進程
close(README);#關閉讀端
select( WRITEME ); #這裡一定要選擇,不然設置的緩存大小不會對WRITEME有效
$| = 1;
open(LOG,"tail -n 2 -f /var/log/alert| ") ||die "Unable to open log file $!\n";
while (<LOG>) {
system(“touch $lockfilename");#加鎖
print WRITEME "Sounds\n12下一頁