W3docs

Функция PHP socket_get_status(): всё, что нужно знать

Узнайте, как использовать функцию socket_get_status() в PHP для проверки состояния потокового соединения, обнаружения таймаутов и анализа буфера.

Когда вы читаете данные из сетевого соединения в PHP или записываете в него, вам нередко нужно знать, активно ли соединение, не истёк ли таймаут чтения и сколько байт ожидает в буфере. Функция socket_get_status() отвечает именно на эти вопросы: она возвращает снимок текущего состояния потока.

В этой главе объясняется, что возвращает socket_get_status(), когда важен каждый из полей, и как безопасно использовать функцию с таймаутами и неблокирующими потоками.

Что такое функция socket_get_status()?

socket_get_status() возвращает текущее состояние потокового ресурса в виде ассоциативного массива. По сути это псевдоним stream_get_meta_data(), поэтому обе функции возвращают одинаковые данные — socket_get_status() просто историческое название, сохранённое для сетевого кода.

Несмотря на название, функция предназначена для ресурсов типа stream — таких, которые возвращают fsockopen(), pfsockopen() или stream_socket_client() — но не для низкоуровневых ресурсов сокетов, созданных через socket_create(). Передача неправильного типа ресурса может вызвать предупреждения об устаревании в PHP 8+ и не даст ожидаемых данных.

Как использовать функцию socket_get_status()

Использовать функцию socket_get_status() несложно. Вот её синтаксис:

Синтаксис PHP функции socket_get_status()

socket_get_status(resource $stream): array

Функция принимает один параметр:

  • $stream: Потоковый ресурс, состояние которого нужно получить.

Она возвращает ассоциативный массив. Наиболее полезные ключи:

КлючТипЗначение
timed_outbooltrue, если последняя операция чтения/записи превысила таймаут потока.
blockedbooltrue, если поток находится в блокирующем режиме.
eofbooltrue, если достигнут конец потока (соединение закрыто).
unread_bytesintБайты, уже считанные во внутренний буфер PHP, но ещё не обработанные.
stream_typestringИспользуемый транспорт, например tcp_socket/ssl.
wrapper_typestringОбёртка, обрабатывающая поток, например http.
modestringРежим доступа, с которым был открыт поток, например r+.

Проверка активности соединения

Вот минимальный пример, открывающий TCP-поток, читающий строку и использующий socket_get_status() для определения, закрыл ли сервер соединение:

Как использовать функцию socket_get_status()?

<?php

$stream = fsockopen("tcp://www.example.com", 80, $errno, $errstr, 30);
if (!$stream) {
    die("Error: $errstr ($errno)");
}

fwrite($stream, "GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n");
$line = fgets($stream);

$status = socket_get_status($stream);
echo $status["eof"] ? "Connection closed by server\n" : "Connection still open\n";

fclose($stream);
?>

Мы используем fsockopen() для создания потока и проверяем успешность его создания перед дальнейшими действиями. После отправки запроса и чтения одной строки с помощью fgets() поле eof показывает, завершила ли удалённая сторона передачу. Всегда закрывайте поток с помощью fclose() после завершения работы.

Обнаружение таймаута чтения

Поле timed_out делает socket_get_status() по-настоящему полезной. Когда вы устанавливаете таймаут чтения с помощью stream_set_timeout() (или socket_set_timeout()), медленное чтение не генерирует исключение — fgets() просто возвращает false. Затем вы вызываете socket_get_status(), чтобы понять почему она вернула false:

<?php

$stream = fsockopen("tcp://www.example.com", 80, $errno, $errstr, 30);
if (!$stream) {
    die("Error: $errstr ($errno)");
}

// Wait at most 2 seconds for data before giving up.
stream_set_timeout($stream, 2);

$line = fgets($stream); // We never sent a request, so nothing arrives.

$status = socket_get_status($stream);
if ($status["timed_out"]) {
    echo "Read timed out\n";
} else {
    echo "Got data\n";
}

fclose($stream);
?>

Поскольку запрос не был отправлен, серверу нечего отвечать, срабатывает двухсекундный таймаут, и скрипт выводит Read timed out. Без socket_get_status() невозможно отличить таймаут от реального окончания потока — в обоих случаях fgets() возвращает false.

Когда использовать socket_get_status()

  • После неудачного чтения. Возврат false из fgets()/fread() неоднозначен; проверьте timed_out и eof, чтобы понять причину.
  • Перед повторным использованием соединения. Проверьте eof, чтобы убедиться, что keep-alive соединение по-прежнему активно перед отправкой следующего запроса.
  • С неблокирующими потоками. Когда вы вызываете stream_set_blocking() для перевода сокета в неблокирующий режим, unread_bytes и blocked помогают анализировать буферизованные данные.

Важные замечания

  • Функция работает только с ресурсами stream — не с ресурсами socket_create(). Для последних используйте socket_last_error() / socket_get_option().
  • socket_get_status() отражает состояние буфера и таймаутов на момент вызова; она не проверяет сеть активно, поэтому значение eof равное false не гарантирует доступность удалённого узла.
  • Сбросьте флаг таймаута, выполнив ещё одно успешное чтение — массив пересчитывается при каждом вызове.

Заключение

Функция socket_get_status() — лёгкий способ проверить состояние потокового сокета в PHP. Наиболее ценное поле — timed_out, позволяющее отличить таймаут чтения от закрытого соединения — то, что одно лишь возвращаемое значение fgets() не позволяет сделать. В сочетании с eof, unread_bytes и средствами управления таймаутом и блокировкой из stream_set_timeout() и stream_set_blocking() функция даёт всю необходимую информацию для надёжной работы с сетевыми соединениями.

Практика

Практика
Какова цель функции socket_get_status() в PHP?
Какова цель функции socket_get_status() в PHP?
Was this page helpful?