PHP сначала fwrite() в сокет, закрытый удаленным сервером, не выдает ошибку

Версия PHP: 5.4.4 для Debian 3.2.54-2 x86_64. Я использую потоковые сокеты. Я создал простые серверные и клиентские приложения, чтобы проиллюстрировать мою проблему:

<?php
$client = false;
$server_sock = stream_socket_server("tcp://127.0.0.1:20015", $errNo, $errorMessage);
if ($server_sock == false) die("Could not bind to socket: {$errNo} - {$errorMessage}"); 
while (true) { 
    if ($client !== false) {
        if (feof($client)) $data = false;
        else $data = stream_get_contents($client);
        if ($data === false) {
            fclose($client);
            $client = false;
            echo "Client disconnected\n";
            continue;
        } else if ($data === "") continue;
        echo "Received: " . $data . "\n";            
    } else {
        $clients = array($server_sock);
        $num_streams = stream_select($clients, $write = null, $except = null, 0, 200000);
        if ($num_streams > 0) {
            if (in_array($server_sock, $clients)) {
                $client = stream_socket_accept($server_sock);
                if ($client) {
                    if(!stream_set_blocking($client, 0)) echo "stream_set_blocking() error\n";
                } else {
                    echo "stream_socket_accept() error\n";
                    $client = false;
                }
            }
        }
    }
}
?>

Код клиента:

<?php
    $client = stream_socket_client("tcp://127.0.0.1:20015", $errNo, $errorMessage);
    if ($client == false) die("Could not connect to server: {$errNo} - {$errorMessage}\n");
    if(!stream_set_blocking($client, 0)) echo "stream_set_blocking() error\n";

    $tick = true;

    while (true) {
        sleep(2);
        if ($tick) $toSend = "TICK "; else $toSend = "TOCK ";
        $tick = !$tick;
        $toSend .= time();
        $num_bytes = fwrite($client, $toSend);
        if ($num_bytes === false || $num_bytes < strlen($toSend)) { echo "fwrite() error\n"; continue; }
        else echo "Data sent: {$toSend}. Bytes: {$num_bytes}\n";
    }
    if (fclose($client)) echo "Socket closed\n";
    else echo "fclose() error\n";
?>

Проблема: если я вручную выключаю сервер (для симуляции потерянного соединения), первый вызов fwrite () (на стороне клиента) после выключения сервера не выдает ошибку. Вызов fwrite () второй раз возвращает 0 и генерирует уведомление PHP "PHP Notice: fwrite(): сбой отправки 15 байтов с ошибкой errno=32 Broken pipe", как и ожидалось. Все, что отправлено с первым вызовом fwrite (), потеряно, но клиент "думает", что все в порядке. В производственной среде после ошибки клиент попытается восстановить соединение и, если это удастся, он попытается повторно отправить данные. Но здесь клиент не полностью осведомлен о ситуации. Почему fwrite () ведет себя так? Я пытался включить режим блокировки в потоке с помощью timeout, fwrite (), а затем получить потоковые метаданные, но кажется, что fwrite () никогда не прерывается, даже если он выдает ошибку. Любые советы или решения?

0 ответов

Другие вопросы по тегам