Нужна ли оптимизация моего основного PHP Socket Server? - PullRequest
2 голосов
/ 22 июня 2009

Как и многие люди, я могу многое сделать с помощью PHP. Одна проблема, с которой я постоянно сталкиваюсь, заключается в том, что другие люди могут сделать это намного чище, гораздо более организованно и гораздо более структурировано. Это также приводит к гораздо более быстрому времени выполнения и гораздо меньшему количеству ошибок.

Я только что закончил писать базовый PHP Socket Server (настоящее ядро) и спрашиваю вас, можете ли вы сказать мне, что я должен делать по-другому, прежде чем я начну расширять ядро. Я не спрашиваю об улучшениях, таких как зашифрованные данные, аутентификация или многопоточность.

Меня больше интересуют вопросы типа «Должен ли я сделать это более объектно-ориентированным способом (с использованием PHP5)?» Или «Общая структура того, как скрипт работает хорошо, или должны быть выполнены некоторые вещи» разные?". По сути, «так должно работать ядро ​​сервера сокетов?»

На самом деле, я думаю, что если я просто покажу вам код здесь, многие из вас сразу увидят возможности для улучшений. Пожалуйста, будь так добр, скажи мне. Спасибо!

#!/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";
?>

Ответы [ 2 ]

0 голосов
/ 04 мая 2010

Я бы переместил данные вашего $ switch в функцию, так как она, вероятно, расширится.

Кроме того, так как похоже, что вы используете текстовый протокол, вы можете захотеть взорвать / strtok, чтобы получить команду первого уровня и проверить ее по массиву допустимых команд. Может также иметь массив, который описывает, какую внутреннюю функцию вызывать, и использовать call_user_func_array для отправки вызова.

0 голосов
/ 22 июня 2009

Одна небольшая вещь, лично я создал бы функцию для вывода вместо простого использования echo, чтобы его было легко отключить, изменить формат и т. Д. Например,

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

и тогда вы можете использовать:

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

вместо

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

Да, и обязательно используйте === вместо == в противном случае вы можете получить некоторые странные результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...