歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> PERL編程 >> Perl進程間通訊研究

Perl進程間通訊研究

日期:2017/3/2 16:33:53   编辑:PERL編程

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下一頁

Copyright © Linux教程網 All Rights Reserved