PHP: Программирование сокетов - Одновременная работа с несколькими сокетами
Индекс материала |
---|
PHP: Программирование сокетов |
Создание клиентских сокетов. |
Создание серверных сокетов |
Одновременная работа с несколькими сокетами |
Все страницы |
Одновременная работа с несколькими сокетами
В листинге, на предыдущей странице был представлен сервер на базе сокетов. Однако он не слишком удобен для реальных, целей, поскольку к нему может выполняться только одно подключение одновременно. Чтобы создать более удобный сервер сокетов, необходимо научиться работать одновременно с множеством сокетов. Чтобы сделать это, понадобится функция socket_select (), синтаксис которой выглядит следующим образом:
socket_select(&$read, &$write, &$error, $sec [, $usec]);
Здесь $read, $write и $error — переданные по ссылке переменные (точнее, массивы). Эти массивы должны содержать список всех сокетов, за которыми нужно наблюдать на предмет чтения, записи и перехвата ошибок соответственно. Например, помещение активного сокета в массив, передаваемый в параметре $read, заставляет РНР проверять, есть ли в этом сокете данные для чтения. Последние два параметра - $sec и необязательный $usec - это значения тайм-аута, управляющие тем, как долго будет ожидать функция socket_select(), прежде чем вернуть управление РНР.
В результате выполнения функция socket_select() возвращает целое число, указывающее общее количество измененных сокетов ( из переданного списка), и модифицирует массивы $read, $write и $error, удаляя из них те элементы, которые не были изменены. В результате каждый из этих массивов будет содержать только список сокетов, отвечающих следующим требованиям:
Сокеты, перечисленные в массиве $read, содержат данные, подлежащие чтению из них, либо входящие подключения к ним.
Сокеты, перечисленные в массиве $write, содержат данные, подлежащие записи в них.
Сокеты, перечисленные в массиве $error, содержат ошибки, которые нужно обработать.
В случае ошибочного завершения socket_select() возвращает булевское значение false.
Для использования этой функции в реальном приложении первым делом должен быть создан сокет, представляющий сервер в целом. Этот главный сокет будет привязан к определенному адресу и порту и начнет прослушивание подключений.
Этот сокет будет также добавлен в массив $read и будет запущен управляемый бесконечный цикл. Затем с помощью функции socket_select() будет организован мониторинг главного сокета на предмет новых подключений. Когда появляется новое подключение, автоматически вызывается функция socket_accept(), что приводит к созданию нового серверного сокета, используемого для взаимодействия с подключенным клиентом.
Этот новый подключенный сокет затем подвергается мониторингу через тот же вызов socket_select() (за счет добавления его к тому же массиву, куда уже добавлен наш главный сокет) и реализуется логика приложения, обеспечивающая функциональность нашего сервера. В листинге ниже представлен работающий пример простого сервера, принимающего настраиваемое число подключений.
Создание многосортного сервера на РНР
<?php set_time_limit(0); $NULL = NULL; $address = "127.0.0.1"; $port = 4545; $max_clients = 10; $client_sockets = array(); $master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); $res = true; $res &= @socket_bind($master, $address, $port); $res &= @socket_listen($master); if(!$res) { die ("Невозможно привязать и прослушивать $address: $port\n"); } $abort = false; $read = array($master); while(!$abort) { $num_changed = socket_select($read, $NULL, $NULL, 0, 10); /* Изменилось что-нибудь? */ if ($num_changed) { /* Изменился ли главный сокет (новое подключение) */ if(in_array($master, $read)) { if(count($client_sockets) < $max_clients) { $client_sockets[]= socket_accept($master); echo "Принято подключение (" . count($client_sockets) . " of $max clients)\n"; } } /* Цикл по всем клиентам с проверкой изменений в каждом из них */ foreach($client_sockets as $key => $client) { /* Новые данные в клиентском сокете? Прочитать и ответить */ if(in_array($client, $read)) { $input = socket_read($client, 1024); if($input === false) { socket_shutdown($client); unset($client_sockets[$key]); } else { $input = trim($input); if (!@socket_write($client, "Вы сказали: $input\n") ) { socket_close($client); unset ( $client_sockets[$key] ) ; } } if($input == 'exit') { socket_shutdown($master); $abort = true; } }// END IF in_array } // END FOREACH } // END IF ($num_changed) $read = $client_sockets; $read[] = $master; } // END WHILE ?>
Кстати!
В листинге выше вскрыты некоторые ограничения сценарного механизма РНР, которые требуют несколько более сложного обходного пути в форме вызова socket_select():
$num_changed = socket_select($read, $NULL, $NULL, 0, 10);
Обратите внимание на применение переменной с именем $NULL. В РНР для функций, принимающих параметры по ссылке (как это и делает socket_select() в первом приближении), NULL является недопустимым значением. Однако передача NULL в качестве одного или более параметров-списков вполне корректна. Поэтому обходной маневр заключается в присвоении переменной $NULL значения NULL:
$NULL = NULL;
И последующей ее передачи функции socket_select().
Cooper vision clariti 1 day
Однодневные линзы cooper vision clariti 1 day заказывайте онлайн.
www.ochkov.net
Добавить комментарий
Информация копипастерам
Внимание! Копирование контента с сайта, возможно только с разрешения администратора. Т.е. Меня! Я скорее всего разрешу Вам это сделать, в обмен на живую ссылку, на статью оригинал.