zoukankan      html  css  js  c++  java
  • php非阻塞服务器

    <?php
    
    class PHPSocketServer
    {
      const ERROR = 0;
      const LOG   = 1;
      const DEBUG = 2;
    
      private $aConfig       = NULL;
      private $hSocket       = NULL;
      private $aClients      = array();
      private $iRunning      = 0;
      private $iStartTime    = 0;
      private $iLastActivity = 0;
    
      private static $aDefaults = array
      (
        'main' => array
        (
          'address'          => 'localhost',
          'port'             => 15151,
          'backlog'          => 200,
          'select_timeout'   => 1,
          'pid_file'         => 'phpserver.pid'
        ),
    
        'verbosity' => array
        (
          'echo_log'         => 1,
          'echo_debug'       => 0,
          'echo_errors'      => 1,
          'log_errors'       => 1
        )
      );
    
      public function getPidFile()
      {
        return $this->aConfig['main']['pid_file'];
      }
    
      private static function getName( $hSocket )
      {
        return socket_getpeername( $hSocket, $sAddress, $iPort ) ? "$sAddress:$iPort" : "?????:???";
      }
    
      private function log( $sMessage, $iType )
      {
        $sTimeStamp = @strftime( '%c' );
    
        if( $iType == self::ERROR )
        {
          $aBacktrace = debug_backtrace();
          $aBacktrace = $aBacktrace[1];
          $sMessage   = sprintf( '[%s] [E] %s%s%s [%d] : %s', $sTimeStamp, $aBacktrace['class'], $aBacktrace['type'], $aBacktrace['function'], $aBacktrace['line'], $sMessage );
    
          if( $this->aConfig['verbosity']['echo_errors'] )
            printf( "$sMessage
    " );
    
          if( $this->aConfig['verbosity']['log_errors'] )
            error_log( $sMessage );
        }
        else if( $iType == self::DEBUG && $this->aConfig['verbosity']['echo_debug'] )
        {
          echo sprintf( '[%s] [D] : %s', $sTimeStamp, $sMessage )."
    ";
        }
        else if( $iType == self::LOG && $this->aConfig['verbosity']['echo_log'] )
        {
          echo sprintf( '[%s] [L] : %s', $sTimeStamp, $sMessage )."
    ";
        }
      }
    
      /*
       * Handle clients here.
       */
      private function handleClientRequest( $hClient, $iClientIndex )
      {
        /*
         * ...
         */
    
        $this->disconnect( $iClientIndex );
      }
    
      private function disconnect( $i )
      {
        socket_close( $this->aClients[ $i ] );
        $this->aClients[ $i ] = NULL;
      }
    
      private function loadConfiguration( $sConfigFile )
      {
        if( !is_file( $sConfigFile ) || !is_readable( $sConfigFile ) )
          die( "Could not read $sConfigFile.
    " );
    
        else if( !( $this->aConfig = parse_ini_file( $sConfigFile, TRUE ) ) )
          die( "Could not parse $sConfigFile.
    " );
    
        foreach( self::$aDefaults as $sSection => $aDefaultValues )
        {
          if( !isset( $this->aConfig[ $sSection ] ) )
            $this->aConfig[ $sSection ] = array();
    
          foreach( $aDefaultValues as $sName => $sValue )
          {
            if( !isset( $this->aConfig[ $sSection ][ $sName ] ) )
              $this->aConfig[ $sSection ][ $sName ] = $sValue;
          }
        }
      }
    
      public function setConfig( $sSectionName, $sConfigName, $mValue )
      {
        if( !isset( $this->aConfig[ $sSectionName ] ) )
          $this->aConfig[ $sSectionName ] = array();
    
        $this->aConfig[ $sSectionName ][ $sConfigName ] = $mValue;
      }
    
      public function __construct( $sConfigFile )
      {
        $this->loadConfiguration( $sConfigFile );
    
        if( !( $this->hSocket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ) ) )
          $this->log( 'Could not create main socket ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
    
        else if( socket_set_option( $this->hSocket, SOL_SOCKET, SO_REUSEADDR, 1 ) === FALSE )
          $this->log( 'Could not set SO_REUSEADDR flag ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
      }
    
      public function start()
      {
        if( !socket_bind( $this->hSocket, $this->aConfig['main']['address'], $this->aConfig['main']['port'] ) )
          $this->log( 'Could not bind on '.$this->aConfig['main']['address'].':'.$this->aConfig['main']['port'].' ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
    
        else if( !socket_listen( $this->hSocket, $this->aConfig['main']['backlog'] ) )
          $this->log( 'Could not put main socket in listening mode ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
    
        else if( !socket_set_nonblock( $this->hSocket ) )
          $this->log( 'Could not set main socket in non-blocking mode ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
    
        else
        {
          $this->iStartTime = time();
    
          $this->log( 'Server started on '.$this->aConfig['main']['address'].':'.$this->aConfig['main']['port'].' .', self::LOG );
    
          for(;;)
          {
            $aRead = array_merge( array( $this->hSocket ), $this->aClients );
    
            if( socket_select( $aRead, $aWrite, $aExcept, $this->aConfig['main']['select_timeout'] ) )
            {
              if( in_array( $this->hSocket, $aRead ) )
              {
                if( ( $hClient = @socket_accept( $this->hSocket ) ) )
                {
                  $this->aClients[ microtime(TRUE) ] = $hClient;
                  $this->iLastActivity = time();
    
                  $this->log( 'New incoming connection '.self::getName( $hClient ), self::DEBUG );
                }
                else
                  $this->log( 'Could not accept a new connection ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
              }
            }
    
            /*
             * Search for readable clients.
             */
            foreach( $this->aClients as $i => $hClient )
            {
              if( in_array( $hClient, $aRead ) )
              {
                $this->handleClientRequest( $hClient, $i );
              }
            }
    
            /*
             * Remove closed connections.
             */
            $this->aClients = array_filter( $this->aClients );
          }
        }
      }
    
      public function __destruct()
      {
        if( $this->hSocket )
        {
          $this->log( 'Shutting down ...', self::LOG );
    
          foreach( $this->aClients as $sId => $hClient )
          {
            if( $hClient )
              socket_close( $hClient );
          }
    
          socket_close( $this->hSocket );
        }
    
        @unlink( $this->getPidFile() );
      }
    }
    
    ?>
  • 相关阅读:
    Java I/O (1)
    hadoop集群添加新节点
    [kuangbin带你飞]专题三 Dancing Links
    Codeforces Round #580 (Div. 2)(A、B、C)
    2019 年百度之星&#183;程序设计大赛
    [kuangbin专题] KMP
    Codeforces Round #578 (Div. 2)(A、B、C、D、E)
    二维前缀和、差分习题集
    [kuangbin带你飞]专题七 线段树
    Codeforces Round #577 (Div. 2) (A、B、C)
  • 原文地址:https://www.cnblogs.com/trying/p/3368500.html
Copyright © 2011-2022 走看看