PHP Echo-Server

Ein einfacher TCP-Echo-Server implementiert als PHP-Standalone (CLI) Anwendung.

PHP Sockets - (socket.php)
  1. #!/usr/bin/php
  2.  
  3. <?php
  4.     declare(ticks=1); // obsolete in php 5.3.0 and above
  5.  
  6.     function do_terminate()
  7.     {
  8.         global $run_loop;
  9.         $run_loop = false;
  10.         echo "\n\nApplication should terminate\n\n";
  11.     }
  12.  
  13.     function signal_handler($signo)
  14.     {
  15.         switch ($signo) {
  16.             case SIGALRM:
  17.             case SIGQUIT:
  18.             case SIGINT:
  19.             case SIGKILL:
  20.             case SIGTERM:
  21.             case SIGHUP:
  22.             case SIGUSR1:
  23.             case SIGUSR2:
  24.                 echo "Recieve SIGUSR2...\n";
  25.                 do_terminate();
  26.                 break;
  27.             default:
  28.                 echo 'Recieve unknown Signal: ' . $signo . "\n";
  29.         }
  30.     }
  31.  
  32.     global $run_loop;
  33.     $run_loop = true;
  34.  
  35.     // catch signals to terminate the process manually and close the sockets
  36.     pcntl_signal(SIGQUIT, 'signal_handler');
  37.     pcntl_signal(SIGTERM, 'signal_handler');
  38.     pcntl_signal(SIGINT, 'signal_handler');
  39.     pcntl_signal(SIGHUP,  'signal_handler');
  40.     pcntl_signal(SIGUSR1, 'signal_handler');
  41.     pcntl_signal(SIGUSR2, 'signal_handler');
  42.  
  43.     // the script is allowed to run unlimited (FIXME: is this really needed in CLI mode? i think not)
  44.     set_time_limit(0);
  45.  
  46.     // Set the ip and port we will listen on
  47.     $address = 'localhost';
  48.     $port = 22222;
  49.  
  50.     // create a tcp stream socket
  51.     echo 'Create the socket' . "\n";
  52.     $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  53.     if ($socket === false)
  54.     {
  55.         die(socket_strerror(socket_last_error($socket)));
  56.     }
  57.    
  58.     // set socket option, to reuse the socket, even if the adress is already in use
  59.     // this is needed, if the socket was not properly shutdown (from server or from client)
  60.     socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
  61.  
  62.     // bind the socket to address & port
  63.     echo 'Bind the socket.' . "\n";
  64.     if (socket_bind($socket, $address, $port) === false)
  65.     {
  66.         $error = socket_strerror(socket_last_error($socket));
  67.         socket_close($socket);
  68.         die($error);
  69.     }
  70.    
  71.     // Listen for new connections
  72.     echo 'Listen to the socket.' . "\n";
  73.     if (socket_listen($socket) === false)
  74.     {
  75.         $error = socket_strerror(socket_last_error($socket));
  76.         socket_close($socket);
  77.         die($error);
  78.     }
  79.    
  80.  
  81.     $socket_clients = array($socket);
  82.  
  83.     // loop until a signal sets run_loop
  84.     while ($run_loop) {
  85.         // copy the clients array
  86.         $read = $socket_clients;
  87.  
  88.         // recieve a list of clients, that has data to read
  89.         $result = socket_select($read, $write = NULL, $except = NULL, 0, 1000);
  90.  
  91.         if ($result === false)
  92.         {
  93.             $error = socket_strerror(socket_last_error($socket));
  94.             socket_close($socket); 
  95.             die($error);
  96.         }
  97.         else if ($result > 0)
  98.         {
  99.  
  100.             // check for new connections
  101.             if (in_array($socket, $read)) {
  102.                 $socket_new = socket_accept($socket);
  103.                 $socket_clients[] = $socket_new;
  104.                
  105.                 socket_getpeername($socket_new, $ip, $port);
  106.                 echo 'New Peer has connected: ' . $ip . ':' . $port . "\n";
  107.  
  108.                 socket_write($socket_new, 'DeSoft ChatServer (Members: ' . (count($socket_clients) - 1) . ")\n");
  109.                
  110.                 // unset the socket from read array
  111.                 unset($read[array_search($socket, $read)]);
  112.             }
  113.  
  114.             // now loop through the other sockets in the read array, and read the data
  115.             foreach ($read as $socket_read) {
  116.                 // read data
  117.                 $buffer_read = socket_read($socket_read, 4096, PHP_BINARY_READ); //in PHP_NORMAL_READ, you should use @socket_read, to supress the error, if a client disconnect
  118.  
  119.                 // has client socket be closed? (works in PHP_NORMAL_READ)
  120.                 if ($buffer_read === false) {
  121.                     $key = array_search($socket_read, $socket_clients);
  122.                     unset($socket_clients[$key]);
  123.                     echo "Client disconnected.\n";
  124.                 }
  125.                 else // socket not closed, data to read
  126.                 {
  127.                     $buffer_read = trim($buffer_read);
  128.  
  129.                     if (!empty($buffer_read)) {
  130.                         // broadcast the message, to all other clients
  131.                         foreach ($socket_clients as $socket_write)
  132.                         {
  133.                             if (($socket_write != $socket) && ($socket_write != $socket_read))
  134.                             {
  135.                                 socket_write($socket_write, $buffer_read . "\n");
  136.                             }
  137.                         }
  138.                     }
  139.                     else // has client socket be closed? (works in PHP_BINARY_READ)
  140.                     {
  141.                         $key = array_search($socket_read, $socket_clients);
  142.                         unset($socket_clients[$key]);
  143.                         echo "Client disconnected.\n";                     
  144.                     }
  145.                 }
  146.             }
  147.         }
  148.     }
  149.  
  150.     // close the Server
  151.     echo "Shutdown Server.\n";
  152.     socket_close($socket);
  153. ?>
  154.