2009-06-22 5 views
2

Comme beaucoup de gens, je peux faire beaucoup de choses avec PHP. Un problème que je rencontre constamment est que d'autres personnes peuvent le faire beaucoup plus propre, beaucoup plus organisé et beaucoup plus structuré. Cela entraîne également des temps d'exécution beaucoup plus rapides et beaucoup moins de bugs. Je viens de terminer l'écriture d'un PHP Socket Server basique (le vrai noyau), et je vous demande si vous pouvez me dire ce que je devrais faire avant de commencer à développer le noyau. Je ne parle pas d'améliorations telles que les données cryptées, l'authentification ou le multi-threading. Je m'interroge davantage sur des questions comme "devrais-je le faire de manière plus orientée objet (en utilisant PHP5)?", Ou "est la structure générale de la façon dont le script fonctionne bien, ou devrait-il y avoir des choses fait différent? ". Fondamentalement, "est-ce la façon dont le noyau d'un serveur de socket devrait fonctionner?"Est-ce que mon PHP Socket Server de base a besoin d'optimisation?

En fait, je pense que si je vous montre le code ici, beaucoup d'entre vous verront immédiatement des améliorations. S'il vous plaît soyez si gentil de me le dire. Merci!

#!/usr/bin/php -q 
<? 
// config 
$timelimit = 180; // amount of seconds the server should run for, 0 = run indefintely 
$address = $_SERVER['SERVER_ADDR']; // the server's external IP 
$port = 9000; // the port to listen on 
$backlog = SOMAXCONN; // the maximum of backlog incoming connections that will be queued for processing 

// configure custom PHP settings 
error_reporting(1); // report all errors 
ini_set('display_errors', 1); // display all errors 
set_time_limit($timelimit); // timeout after x seconds 
ob_implicit_flush(); // results in a flush operation after every output call 

//create master IPv4 based TCP socket 
if (!($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) die("Could not create master socket, error: ".socket_strerror(socket_last_error())); 

// set socket options (local addresses can be reused) 
if (!socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1)) die("Could not set socket options, error: ".socket_strerror(socket_last_error())); 

// bind to socket server 
if (!socket_bind($master, $address, $port)) die("Could not bind to socket server, error: ".socket_strerror(socket_last_error())); 

// start listening 
if (!socket_listen($master, $backlog)) die("Could not start listening to socket, error: ".socket_strerror(socket_last_error())); 

//display startup information 
echo "[".date('Y-m-d H:i:s')."] SERVER CREATED (MAXCONN: ".SOMAXCONN.").\n"; //max connections is a kernel variable and can be adjusted with sysctl 
echo "[".date('Y-m-d H:i:s')."] Listening on ".$address.":".$port.".\n"; 
$time = time(); //set startup timestamp 

// init read sockets array 
$read_sockets = array($master); 

// continuously handle incoming socket messages, or close if time limit has been reached 
while ((!$timelimit) or (time() - $time < $timelimit)) { 
    $changed_sockets = $read_sockets; 
    socket_select($changed_sockets, $write = null, $except = null, null); 
    foreach($changed_sockets as $socket) { 
     if ($socket == $master) { 
      if (($client = socket_accept($master)) < 0) { 
       echo "[".date('Y-m-d H:i:s')."] Socket_accept() failed, error: ".socket_strerror(socket_last_error())."\n"; 
       continue; 
      } else { 
       array_push($read_sockets, $client); 
       echo "[".date('Y-m-d H:i:s')."] Client #".count($read_sockets)." connected (connections: ".count($read_sockets)."/".SOMAXCONN.")\n"; 
      } 
     } else { 
      $data = @socket_read($socket, 1024, PHP_NORMAL_READ); //read a maximum of 1024 bytes until a new line has been sent 
      if ($data === false) { //the client disconnected 
       $index = array_search($socket, $read_sockets); 
       unset($read_sockets[$index]); 
       socket_close($socket); 
       echo "[".date('Y-m-d H:i:s')."] Client #".($index-1)." disconnected (connections: ".count($read_sockets)."/".SOMAXCONN.")\n"; 
      } else { 
       if ($data = trim($data)) { //remove whitespace and continue only if the message is not empty 
        switch ($data) { 
         case "exit": //close connection when exit command is given 
          $index = array_search($socket, $read_sockets); 
          unset($read_sockets[$index]); 
          socket_close($socket); 
          echo "[".date('Y-m-d H:i:s')."] Client #".($index-1)." disconnected (connections: ".count($read_sockets)."/".SOMAXCONN.")\n"; 
          break; 
         default: //for experimental purposes, write the given data back 
          socket_write($socket, "\n you wrote: ".$data); 
        } 
       } 
      } 
     } 
    } 
} 
socket_close($master); //close the socket 
echo "[".date('Y-m-d H:i:s')."] SERVER CLOSED.\n"; 
?> 

Répondre

0

Une petite chose, je personnellement créer une fonction pour la sortie au lieu d'utiliser simplement l'écho, de cette façon il est facile de l'éteindre, changer le format, etc .. par exemple

function log($message = '') 
{ 
    echo '['.date('Y-m-d H:i:s').']'.$message; 
} 

et vous pouvez utiliser:

log("SERVER CREATED (MAXCONN: ".SOMAXCONN.").\n"); 

au lieu de

echo "[".date('Y-m-d H:i:s')."] SERVER CREATED (MAXCONN: ".SOMAXCONN.").\n"; 

Oh et assurez-vous d'utiliser === au lieu de == sinon vous pourriez obtenir des résultats étranges.

+0

J'aurais dû le mentionner mais les échos étaient juste là à des fins expérimentales. Merci quand même. J'aurais dû dire que je remettais en question l'efficacité de la structure du serveur socket plus. Par exemple. si je devrais vraiment boucler des choses comme je le fais ou s'il y a de meilleures façons de le faire. – Tom

0

Je déplacerais vos données $ switch dans une fonction car cela va probablement se développer. De plus, comme il semble que vous utilisiez un protocole basé sur du texte, vous pourriez vouloir faire exploser/strtok pour obtenir la commande de premier niveau et la comparer à un tableau de commandes valides. Pourrait également avoir un tableau qui décrit la fonction interne à appeler et utiliser call_user_func_array pour répartir l'appel.

Questions connexes