用户操作
[即时聊天] [发私信] [加为好友]
heiyelurenID:heiyeshuwu
890856次访问,排名39好友93人,关注者142
既然决定远行,便只顾风雨兼程。
heiyeshuwu的文章
原创 282 篇
翻译 3 篇
转载 209 篇
评论 517 篇
heiyeluren的公告

联系方式:


访问统计: free hit counter code
FeedSky订阅:
FeedSky订阅
最近评论
heiyeluren:注册发帖后才能下载。。。。不知道论坛咋设置。。。 :-)
kong:注册了也不能下载.....提示您的操作将会导致您的 金钱 低于系统规定的下限值 0
赵舜尧:感谢博主的分享,期待你的“下章接着讲述数据分割和散列方面的内容”
adobe cs4:呃,LAMP经典应用……
俺的
Adobe cs4也是
bluehouse1985:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
文章分类
收藏
    相册
    技术图片
    搜索引擎
    ::eYou::
    kevin world
    lewis - 老吕
    qyb - BT的花
    Realzay的blog
    叶金荣
    天堂地狱鬼-dulao5's Blog
    沙漠之周
    狐狸糊涂
    老韩
    與子觀化
    ::Yahoo::
    glemir’s blog
    happy_fish - 分布式文件系统FastDFS
    LinZi's Blog
    Rainx
    stauren
    互联网,请记住我 - 162同学的技术博客
    冰的河
    小蚂蚁同学滴测试博客
    张彪同学
    随网之舞 - kaven的DHTML博客
    风雪之隅
    ::朋友::
    【推荐】中文分类网
    DDR的博客
    kevin world
    miky
    PHPCup.cn论坛
    俺兄弟的blog
    冰河的技术博客:心随风动
    好旅网
    小少的技术博客
    无尘居
    晋陵路人的Blog
    李天华同学滴技术博客
    沙狐部落
    轻量级的editor
    ::网友::
    blankyao同学
    Code & Stock.
    LionD8的Blog
    MooPHP - 轻量级PHP框架
    Phzzy
    张贺同学的博客
    技术大牛老余的博客
    抚琴居
    旋木木同学滴博客
    矛盾网
    程序人生
    邢红瑞的blog
    阿健的博客
    :PHP博客:
    .: Easy style :.
    [琴剑楼]
    CoolCode.cn
    Haohappy的Blog
    Hightman
    iwind的blog
    Javascript开发站
    JD Space
    Nio's Weblog
    Open Source PHP
    PHP面对对象
    SourceForge.net
    trip的专栏
    UGIA.cn
    windix's blog
    Windix's Weblog
    一个藏袍
    俊麟 Michael`s blog
    偶然的blog
    刘敏的blog
    大龄青年的Blog
    廖宇雷的blog
    懒猫开始新生活blog
    某人的栖息地
    王春生的博客
    神仙
    :牛人blog:
    DBA notes
    http://blog.csdn.net/tingya/
    侯捷网站
    孟岩
    搜索引擎研究
    方舟
    王咏刚的BLOG
    竹笋炒肉
    荣耀
    车东[Blog^2]
    透明思考
    陈硕的Blog
    DHTML
    DHTMLGoodies
    FCKEditor
    Google Code
    Google Web Toolkit
    HTML Goodies
    HTML.it
    HTMLAre
    HTMLdog
    JavaScript Kit
    jQuery
    KindEditor
    Prototype
    TinyMCE
    W3 Schools
    Yahoo JavaScript Developer Center
    Yahoo! Developer Network
    Yahoo! UI Library (YUI)
    网页设计师Web标准
    Java国内站
    ChinaJavaWorld.com技术论坛
    IBM developerWorks 中国: Java
    Java中文站
    Java开源大全
    Java爱好者
    JR - Java翻译站
    J道-JDON
    Matrix: 与Java共舞
    中国Java开发网
    中文java技术网
    PHP国内站点
    CSDN PHP论坛
    Discuz!
    FleaPHP
    Google--PHP用户组
    IBM DeveloperWorks
    JavsScript技术讨论
    Nirvana Studio
    OpenPHP.cn
    PHPChina
    TiM Club
    中文 PFC 1.0 手册--PHP5的开发包
    中文 PFC 1.0 手册--PHP5的开发包
    中文PHP网
    太平洋--PHP开发区
    爱MySQL
    超越PHP
    PHP国外站点
    ADOdb
    Agavi Framework
    Cake PHP
    MySQL Performance Blog
    MySQL Performance Blog
    Nonaweb
    PEAR
    PECL
    PECL Windows
    PHP Builder
    PHP Classes
    PHP Classes
    PHP New Download
    PHP Security Consortium
    php.MVC
    php.MVC
    PHPkitchen(OO & MVC)
    phpPatterns
    PHP国外图书下载
    smart template
    Smarty
    SourceForge.net
    Symfony Framework
    Zend
    Zend Framework
    Unix C/C++
    Free Gentux
    周立发的blog(Linux C)
    Unix/Linux
    BSD智库
    ChinaUnix
    FreeBSDChina
    FreeLAMP
    IBM开发者Linux专区
    Linux Byte
    LinuxKit
    LinuxTS
    Linux伊甸园
    Linux技术中坚站
    Linux非常空间
    Love Unix
    NetBSD&OpenBSD中文用户组
    NetBSD中国社区
    Oracle中国用户讨论组
    OurLinux
    Unix中文
    Unix中文
    Unix中文宝库
    中国Linux公社
    中国Unix用户技术论坛
    中文FreeBSD用户组
    永远的Unix
    炎黄角马
    程序设计
    CSDN
    IBM开发者中心
    Microsoft TechNet: 主页
    MSDN 中文网站
    PHP中文站
    Sun技术社区
    中国IT认证实验室--企业应用技术
    中国协议分析网
    喜悦国际村
    太平洋电脑网---开发特区
    实用网站
    veBook(国外大量免费图书下载网站)
    Whois.net
    中国Web信息博物馆
    中国互联网络信息中心whois查询
    服务器系统信息查看
    网络安全
    AnySide.com
    CGI Secutiry
    K-OTik Security Monitoring
    Linux Security
    Packet Storm Security
    PHP Secure
    RFC中文文档索引
    Safemode.org
    SecuriTeam.com
    Security Corporation
    SecurityFocus
    SecurityTracker
    Zone-h (区域黑客,每天公布各国被黑的网站)
    中华安全网
    中国信息安全组织
    国家计算机网络应急处理中心
    安全天使
    安全焦点
    幻影旅团
    绿盟科技
    网络安全评估中心(cnns )
    在线手册
    Apache2.0中文文档
    Beyond Linux From Scratch
    Debian参考手册
    FreeBSD Porter 手册
    FreeBSD使用手册
    Linux C函数中文参考手册
    MySQL 4.1.0 中文参考手册
    NetBSD在线手册
    OpenBSD在线FAQ
    PHP ADODB 1.99版手册中文翻译(Tripc)
    PHP中文手册(国内)
    PHP中文手册(国外)
    PostgreSQL中文文档
    Red Hat Linux 9入门指南
    Red Hat Linux 9安装指南
    Red Hat Linux 9定制手册
    中国OSS技术手册中心
    技术文档手册中心-ChinaUnix
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    转载 [转]用PHP构建一个简易监视引擎收藏

    新一篇: [转]epoll给我们带来了什么 | 旧一篇: GB2312汉字拼音对照表

     

    来源: http://dev.yesky.com/web/263/2638263.shtml

    摘要在本文中,让我们共同探讨基于PHP语言构建一个基本的服务器端监视引擎的诸多技巧及注意事项,并给出完整的源码实现。

      一. 更改工作目录的问题

      当你编写一个监视程序时,让它设置自己的工作目录通常更好些。这样以来,如果你使用一个相对路径读写文件,那么,它会根据情况自动处理用户期望存放文件的位置。总是限制程序中使用的路径尽管是一种良好的实践;但是,却失去了应有的灵活性。因此,改变你的工作目录的最安全的方法是,既使用chdir()也使用chroot()。

      chroot()可用于PHP的CLI和CGI版本中,但是却要求程序以根权限运行。chroot()实际上把当前进程的路径从根目录改变到指定的目录。这使得当前进程只能执行存在于该目录下的文件。经常情况下,chroot()由服务器作为一个"安全设备"使用以确保恶意代码不会修改一个特定的目录之外的文件。请牢记,尽管chroot()能够阻止你访问你的新目录之外的任何文件,但是,任何当前打开的文件资源仍然能够被存取。例如,下列代码能够打开一个日志文件,调用chroot()并切换到一个数据目录;然后,仍然能够成功地登录并进而打开文件资源:

    <?php
    $logfile = fopen("/var/log/chroot.log", "w");
    chroot("/Users/george");
    fputs($logfile, "Hello From Inside The Chroot\n");
    ?>

      如果一个应用程序不能使用chroot(),那么你可以调用chdir()来设置工作目录。例如,当代码需要加载特定的代码(这些代码能够在系统的任何地方被定位时),这是很有用的。注意,chdir()没有提供安全机制来防止打开未授权的文件。

      二. 放弃特权

      当编写Unix守护程序时,一种经典的安全预防措施是让它们放弃所有不需要的特权;否则,拥有不需要的特权容易招致不必要的麻烦。在代码(或PHP本身)中含有漏洞的情况下,通过确保一个守护程序以最小权限用户身份运行,往往能够使损失减到最小。

      一种实现此目的的方法是,以非特权用户身份执行该守护程序。然而,如果程序需要在一开始就打开非特权用户无权打开的资源(例如日志文件,数据文件,套接字,等等)的话,这通常是不够的。

      如果你以根用户身份运行,那么你能够借助于posix_setuid()和posiz_setgid()函数来放弃你的特权。下面的示例把当前运行程序的特权改变为用户nobody所拥有的那些权限:

    $pw=posix_getpwnam('nobody');
    posix_setuid($pw['uid']);
    posix_setgid($pw['gid']);

      就象chroot()一样,任何在放弃特权之前被打开的特权资源都会保持为打开,但是不能创建新的资源。

      三. 保证排它性

      你可能经常想实现:一个脚本在任何时刻仅运行一个实例。为了保护脚本,这是特别重要的,因为在后台运行容易导致偶然情况下调用多个实例。

      保证这种排它性的标准技术是,通过使用flock()来让脚本锁定一个特定的文件(经常是一个加锁文件,并且被排它式使用)。如果锁定失败,该脚本应该输出一个错误并退出。下面是一个示例:

    $fp=fopen("/tmp/.lockfile","a");
    if(!$fp || !flock($fp, LOCK_EX | LOCK_NB)) {
     fputs(STDERR, "Failed to acquire lock\n");
     exit;
    }
    /*成功锁定以安全地执行工作*/

      注意,有关锁机制的讨论涉及较多内容,在此不多加解释。

     

    四. 构建监视服务

      在这一节中,我们将使用PHP来编写一个基本的监视引擎。因为你不会事先知道怎样改变,所以你应该使它的实现既灵活又具可能性。
    该记录程序应该能够支持任意的服务检查(例如,HTTP和FTP服务)并且能够以任意方式(通过电子邮件,输出到一个日志文件,等等)记录事件。你当然想让它以一个守护程序方式运行;所以,你应该请求它输出其完整的当前状态。

      一个服务需要实现下列抽象类:

    abstract class ServiceCheck {
     const FAILURE = 0;
     const SUCCESS = 1;
     protected $timeout = 30;
     protected $next_attempt;
     protected $current_status = ServiceCheck::SUCCESS;
     protected $previous_status = ServiceCheck::SUCCESS;
     protected $frequency = 30;
     protected $description;
     protected $consecutive_failures = 0;
     protected $status_time;
     protected $failure_time;
     protected $loggers = array();
     abstract public function __construct($params);
     public function __call($name, $args)
     {
      if(isset($this->$name)) {
       return $this->$name;
      }
     }
     public function set_next_attempt()
     {
      $this->next_attempt = time() + $this->frequency;
     }
     public abstract function run();
     public function post_run($status)
     {
      if($status !== $this->current_status) {
       $this->previous_status = $this->current_status;
      }
      if($status === self::FAILURE) {
       if( $this->current_status === self::FAILURE ) {
        $this->consecutive_failures++;
       }
       else {
        $this->failure_time = time();
       }
      }
      else {
       $this->consecutive_failures = 0;
      }
      $this->status_time = time();
      $this->current_status = $status;
      $this->log_service_event();
     }
     public function log_current_status()
     {
      foreach($this->loggers as $logger) {
       $logger->log_current_status($this);
      }
     }
     private function log_service_event()
     {
      foreach($this->loggers as $logger) {
       $logger->log_service_event($this);
      }
     }
     public function register_logger(ServiceLogger $logger)
     {
      $this->loggers[] = $logger;
     }
    }

      上面的__call()重载方法提供对一个ServiceCheck对象的参数的只读存取操作:

      · timeout-在引擎终止检查之前,这一检查能够挂起多长时间。

      · next_attempt-下次尝试连接到服务器的时间。

      · current_status-服务的当前状态:SUCCESS或FAILURE。

      · previous_status-当前状态之前的状态。

      · frequency-每隔多长时间检查一次服务。

      · description-服务描述。

      · consecutive_failures-自从上次成功以来,服务检查连续失败的次数。

      · status_time-服务被检查的最后时间。

      · failure_time-如果状态为FAILED,则它代表发生失败的时间。

      这个类还实现了观察者模式,允许ServiceLogger类型的对象注册自身,然后当调用log_current_status()或log_service_event()时调用它。

      这里实现的关键函数是run(),它负责定义应该怎样执行检查。如果检查成功,它应该返回SUCCESS;否则返回FAILURE。

      当定义在run()中的服务检查返回后,post_run()方法被调用。它负责设置对象的状态并实现记入日志。

      ServiceLogger接口:指定一个日志类仅需要实现两个方法:log_service_event()和log_current_status(),它们分别在当一个run()检查返回时和当实现一个普通状态请求时被调用。

      该接口如下所示:

    interface ServiceLogger {
     public function log_service_event(ServiceCheck$service);
     public function log_current_status(ServiceCheck$service);
    }

      最后,你需要编写引擎本身。该想法类似于在前一节编写简单程序时使用的思想:服务器应该创建一个新的进程来处理每一次检查并使用一个SIGCHLD处理器来检测当检查完成时的返回值。可以同时检查的最大数目应该是可配置的,从而可以防止对系统资源的过渡使用。所有的服务和日志都将在一个XML文件中定义。

      下面是定义该引擎的ServiceCheckRunner类:

    class ServiceCheckRunner {
     private $num_children;
     private $services = array();
     private $children = array();
     public function _ _construct($conf, $num_children)
     {
      $loggers = array();
      $this->num_children = $num_children;
      $conf = simplexml_load_file($conf);
      foreach($conf->loggers->logger as $logger) {
       $class = new Reflection_Class("$logger->class");
       if($class->isInstantiable()) {
        $loggers["$logger->id"] = $class->newInstance();
       }
       else {
        fputs(STDERR, "{$logger->class} cannot be instantiated.\n");
        exit;
       }
      }
      foreach($conf->services->service as $service) {
       $class = new Reflection_Class("$service->class");
       if($class->isInstantiable()) {
        $item = $class->newInstance($service->params);
        foreach($service->loggers->logger as $logger) {
         $item->register_logger($loggers["$logger"]);
        }
        $this->services[] = $item;
       }
       else {
        fputs(STDERR, "{$service->class} is not instantiable.\n");
        exit;
       }
      }
     }
     private function next_attempt_sort($a, $b){
      if($a->next_attempt() == $b->next_attempt()) {
       return 0;
      }
      return ($a->next_attempt() < $b->next_attempt())? -1 : 1;
     }
     private function next(){
      usort($this->services,array($this,'next_attempt_sort'));
      return $this->services[0];
     }
     public function loop(){
      declare(ticks=1);
      pcntl_signal(SIGCHLD, array($this, "sig_child"));
      pcntl_signal(SIGUSR1, array($this, "sig_usr1"));
      while(1) {
       $now = time();
       if(count($this->children)< $this->num_children) {
        $service = $this->next();
        if($now < $service->next_attempt()) {
         sleep(1);
         continue;
        }
        $service->set_next_attempt();
        if($pid = pcntl_fork()) {
         $this->children[$pid] = $service;
        }
        else {
         pcntl_alarm($service->timeout());
         exit($service->run());
        }
       }
      }
     }
     public function log_current_status(){
      foreach($this->services as $service) {
       $service->log_current_status();
      }
     }
     private function sig_child($signal){
      $status = ServiceCheck::FAILURE;
      pcntl_signal(SIGCHLD, array($this, "sig_child"));
      while(($pid = pcntl_wait($status, WNOHANG)) > 0){
       $service = $this->children[$pid];
       unset($this->children[$pid]);
       if(pcntl_wifexited($status) && pcntl_wexitstatus($status) ==ServiceCheck::SUCCESS)
       {
        $status = ServiceCheck::SUCCESS;
       }
       $service->post_run($status);
      }
     }
     private function sig_usr1($signal){
      pcntl_signal(SIGUSR1, array($this, "sig_usr1"));
      $this->log_current_status();
     }
    }

      这是一个很复杂的类。其构造器读取并分析一个XML文件,创建所有的将被监视的服务,并创建记录它们的日志程序。

      loop()方法是该类中的主要方法。它设置请求的信号处理器并检查是否能够创建一个新的子进程。现在,如果下一个事件(以next_attempt时间CHUO排序)运行良好,那么一个新的进程将被创建。在这个新的子进程内,发出一个警告以防止测试持续时间超出它的时限,然后执行由run()定义的测试。

      还存在两个信号处理器:SIGCHLD处理器sig_child(),负责收集已终止的子进程并执行它们的服务的post_run()方法;SIGUSR1处理器sig_usr1(),简单地调用所有已注册的日志程序的log_current_status()方法,这可以用于得到整个系统的当前状态。

      当然,这个监视架构并不没有做任何实际的事情。但是首先,你需要检查一个服务。下列这个类检查是否你从一个HTTP服务器取回一个"200 Server OK"响应:

    class HTTP_ServiceCheck extends ServiceCheck{
     public $url;
     public function _ _construct($params){
      foreach($params as $k => $v) {
       $k = "$k";
       $this->$k = "$v";
      }
     }
     public function run(){
      if(is_resource(@fopen($this->url, "r"))) {
       return ServiceCheck::SUCCESS;
      }
      else {
       return ServiceCheck::FAILURE;
      }
     }
    }

      与你以前构建的框架相比,这个服务极其简单,在此恕不多描述。

    五. 示例ServiceLogger进程

      下面是一个示例ServiceLogger进程。当一个服务停用时,它负责把一个电子邮件发送给一个待命人员:

    class EmailMe_ServiceLogger implements ServiceLogger {
     public function log_service_event(ServiceCheck$service)
     {
      if($service->current_status ==ServiceCheck::FAILURE) {
       $message = "Problem with{$service->description()}\r\n";
       mail('oncall@example.com', 'Service Event',$message);
       if($service->consecutive_failures() > 5) {
        mail('oncall_backup@example.com', 'Service Event', $message);
       }
      }
     }
     public function log_current_status(ServiceCheck$service){
      return;
     }
    }

      如果连续失败五次,那么该进程还把一个消息发送到一个备份地址。注意,它并没有实现一个有意义的log_current_status()方法。

      无论何时象如下这样改变一个服务的状态,你都应该实现一个写向PHP错误日志的ServiceLogger进程:

    class ErrorLog_ServiceLogger implements ServiceLogger {
     public function log_service_event(ServiceCheck$service)
     {
      if($service->current_status() !==$service->previous_status()) {
       if($service->current_status() ===ServiceCheck::FAILURE) {
        $status = 'DOWN';
       }
       else {
        $status = 'UP';
       }
       error_log("{$service->description()} changed status to $status");
      }
     }
     public function log_current_status(ServiceCheck$service)
     {
      error_log("{$service->description()}: $status");
     }
    }

      该log_current_status()方法意味着,如果进程发送一个SIGUSR1信号,它将把其完整的当前状态复制到你的PHP错误日志中。
      
      该引擎使用如下的一个配置文件:

    <config>
     <loggers>
      <logger>
       <id>errorlog</id>
       <class>ErrorLog_ServiceLogger</class>
      </logger>
      <logger>
       <id>emailme</id>
       <class>EmailMe_ServiceLogger</class>
      </logger>
     </loggers>
     <services>
      <service>
       <class>HTTP_ServiceCheck</class>
       <params>
        <description>OmniTI HTTP Check</description>
        <url>http://www.omniti.com</url>
        <timeout>30</timeout>
        <frequency>900</frequency>
       </params>
       <loggers>
        <logger>errorlog</logger>
        <logger>emailme</logger>
       </loggers>
      </service>
     <service>
     <class>HTTP_ServiceCheck</class>
     <params>
      <description>Home Page HTTP Check</description>
      <url>http://www.schlossnagle.org/~george</url>
      <timeout>30</timeout>
      <frequency>3600</frequency>
     </params>
     <loggers>
      <logger>errorlog</logger>
     </loggers>
    </service>
    </services>
    </config>

      当传递这个XML文件时,ServiceCheckRunner的构造器对于每一个指定的日志实例化一个日志记录程序。然后,它相应于每一个指定的服务实例化一个ServiceCheck对象。

      注意 该构造器使用Reflection_Class类来实现该服务和日志类的内在检查-在你试图实例化它们之前。尽管这是不必要的,但是它很好地演示了PHP 5中新的反射(Reflection)API的使用。除了这些类以外,反射API还提供一些类来实现对PHP中几乎任何内部实体(类,方法或函数)的内在检查。

      为了使用你构建的引擎,你仍然需要一些包装代码。监视程序应该会禁止你试图两次启动它-你不需要对每一个事件建立两份消息。当然,该监视程序还应该接收包括下列选项在内的一些选项:

    选项 描述
    [-f] 引擎的配置文件的一个位置,默认是monitor.xml。
    [-n] 引擎允许的子进程池的大小,默认是5。
    [-d] 一个停用该引擎的守护功能的标志。在你编写一个把信息输出到stdout或stderr的调试ServiceLogger进程时,这是很有用的。

      下面是最终的监视程序脚本,它分析选项,保证排它性并且运行服务检查:

    require_once "Service.inc";
    require_once "Console/Getopt.php";
    $shortoptions = "n:f:d";
    $default_opts = array('n' => 5, 'f' =>'monitor.xml');
    $args = getOptions($default_opts, $shortoptions,null);
    $fp = fopen("/tmp/.lockfile", "a");
    if(!$fp || !flock($fp, LOCK_EX | LOCK_NB)) {
     fputs($stderr, "Failed to acquire lock\n");
     exit;
    }
    if(!$args['d']) {
     if(pcntl_fork()) {
      exit;
     }
     posix_setsid();
     if(pcntl_fork()) {
      exit;
     }
    }
    fwrite($fp, getmypid());
    fflush($fp);
    $engine = new ServiceCheckRunner($args['f'],$args['n']);
    $engine->loop();

      注意,这个示例使用了定制的getOptions()函数。

      在编写一个适当的配置文件后,你可以按如下方式启动该脚本:

      > ./monitor.php -f /etc/monitor.xml

      这可以保护并继续监视直到机器被关掉或该脚本被杀死。

      这个脚本相当复杂,但是仍然存在一些容易改进的地方,这些只好留给读者作为练习之用:

      · 添加一个重新分析配置文件的SIGHUP处理器以便你能够在不启动服务器的情况下改变配置。

      · 编写一个能够登录到一个数据库的ServiceLogger以用于存储查询数据。

      · 编写一个Web前端程序以为整个监视系统提供一种良好的GUI。

     

    发表于 @ 2007年05月28日 22:04:00|评论(loading...)|收藏

    新一篇: [转]epoll给我们带来了什么 | 旧一篇: GB2312汉字拼音对照表

    评论:没有评论。

    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © heiyeluren