Socket last error: примеры (PHP)
socket_last_error(resource socket): intОсновы функции socket_last_error
Функция socket_last_error возвращает последнюю ошибку, которая произошла при работе с сокетами. Она используется для отладки сетевых операций после вызовов функций вроде socket_connect, socket_bind или socket_read.
Функция принимает один необязательный аргумент:
- $socket (Socket|null) - ресурс сокета, созданный функцией
socket_create. Если переданnullили аргумент опущен, функция возвращает последнюю ошибку глобального контекста сокетов (до PHP 8.0.0) или вызывает ошибку (начиная с PHP 8.0.0).
Примеры использования
Получение кода ошибки после неудачного подключения:
<?
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// Пытаемся подключиться к несуществующему порту
if (!socket_connect($socket, '127.0.0.1', 9999)) {
$error_code = socket_last_error($socket);
$error_msg = socket_strerror($error_code);
echo "Код ошибки: $error_code, сообщение: $error_msg";
}
socket_close($socket);
?>Код ошибки: 111, сообщение: Connection refused
Версия для PHP до 8.0.0:
<?
// В старых версиях можно было вызвать без аргумента
$socket = socket_create(AF_INET, SOCK_STREAM, 999); // Неверный протокол
if ($socket === false) {
$error_code = socket_last_error(); // Без параметра
echo "Код: $error_code";
}
?>Альтернативные функции в PHP
Возвращает массив с информацией о сокете, включая ошибки в потоковом контексте. Используется чаще для потоков, чем для чистых сокетов.
Сбрасывает последнюю ошибку сокета или глобальную ошибку. Полезно использовать перед операцией, чтобы избежать обработки старых ошибок.
Не является прямой альтернативой, но используется вместе с socket_last_error для получения текстового описания кода ошибки.
Аналоги в других языках
Socket last error в Python
Используется исключение socket.error или метод socket.getsockopt:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('127.0.0.1', 9999))
except socket.error as e:
print(f'Ошибка: {e.errno} - {e.strerror}')Ошибки обрабатываются через события 'error' или колбэки:
const net = require('net');
const client = net.connect({port: 9999}, () => {});
client.on('error', (err) => {
console.log(`Код: ${err.code}, сообщение: ${err.message}`);
});Socket last error в C
Используется глобальная переменная errno и функция perror:
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
printf("Ошибка %d: %s", errno, strerror(errno));
}Типичные ошибки
Вызов функции без параметра приводит к фатальной ошибке:
<? // PHP 8.0 и выше $error = socket_last_error(); // TypeError ?>
TypeError: socket_last_error() expects exactly 1 argument, 0 given
Передача некорректного сокета:
<? $fake_socket = null; $error = socket_last_error($fake_socket); // В PHP 8 - TypeError ?>
Ошибка может относиться к предыдущей операции:
<? $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_connect($socket, '127.0.0.1', 9999); // Ошибка $error1 = socket_last_error($socket); // Код 111 // Новая операция без ошибки socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); // Но старая ошибка осталась, если не очистить $error2 = socket_last_error($socket); // Все еще 111 ?>
Изменения в версиях PHP
Параметр $socket стал обязательным. Вызов функции без аргумента теперь вызывает TypeError. Глобальное хранилище ошибок сокетов удалено.
Тип параметра $socket изменен с ресурса (resource) на объект Socket.
Добавлена возможность передачи null в качестве аргумента для получения глобальной ошибки сокетов.
Расширенные примеры
Обработка ошибок в цикле select:
<?
$sockets = [];
for ($i = 0; $i < 3; $i++) {
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($sock);
socket_connect($sock, '192.168.1.' . $i, 80);
$sockets[] = $sock;
}
usleep(100000); // Ждем асинхронного подключения
foreach ($sockets as $sock) {
$error = socket_last_error($sock);
if ($error !== 0 && $error !== 115) { // 115 = EINPROGRESS
echo 'Сокет ' . spl_object_id($sock) .
' ошибка: ' . socket_strerror($error) . '
';
socket_clear_error($sock);
}
}
?>Работа с датаграммами:
<?
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, '127.0.0.1', 0);
// Пытаемся отправить на закрытый порт
$sent = socket_sendto($socket, 'test', 4, 0, '127.0.0.1', 9999);
if ($sent === false) {
$error = socket_last_error($socket);
// Для UDP ошибка может не возвращаться сразу
if ($error === 0) {
usleep(10000);
$error = socket_last_error($socket);
}
echo 'UDP ошибка: ' . socket_strerror($error);
}
?>Расширенный обработчик:
<?
class SocketErrorHandler {
private $errors = [];
public function check($socket, string $operation): bool {
$error = socket_last_error($socket);
if ($error !== 0) {
$this->errors[] = [
'time' => microtime(true),
'code' => $error,
'msg' => socket_strerror($error),
'op' => $operation
];
socket_clear_error($socket);
return false;
}
return true;
}
public function getErrors(): array {
return $this->errors;
}
}
$handler = new SocketErrorHandler();
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!socket_connect($sock, 'example.com', 9999)) {
$handler->check($sock, 'connect');
}
print_r($handler->getErrors());
?>Использование с socket_select:
<?
$read = [$socket];
$write = [$socket];
$except = [$socket];
$changed = socket_select($read, $write, $except, 5);
if ($changed === false) {
$error = socket_last_error($socket);
echo 'Select ошибка: ' . socket_strerror($error);
} elseif ($changed > 0) {
if (in_array($socket, $except, true)) {
$error = socket_last_error($socket);
echo 'Исключительная ситуация: ' . socket_strerror($error);
}
}
?>