[PHP]stream_set_timeoutで接続タイムアウトを制御する|ネットワークストリームの安全な読み書き実践ガイド

PHP

はじめに

PHPでネットワーク通信やソケット処理を行う際、相手サーバーからの応答がいつまでも来ないと、スクリプトが永遠に待ち続けてしまいます。本番環境でこれが起きると、プロセスが詰まりサービス全体に影響を及ぼします。

stream_set_timeout は、ストリームの読み書き操作に対して タイムアウト時間を設定する関数です。指定時間内に応答がなければ処理を打ち切り、後続のエラーハンドリングに移ることができます。

この記事では、基本的な使い方から実践的なクラス実装まで、丁寧に解説します。


stream_set_timeout とは

項目内容
関数名stream_set_timeout
PHPバージョンPHP 4.3.0以降
カテゴリストリーム関数
返り値bool(成功時 true、失敗時 false

構文

stream_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool

パラメータ

パラメータ説明
$streamresource対象のストリームリソース
$secondsintタイムアウトの秒数部分
$microsecondsintタイムアウトのマイクロ秒部分(省略可、デフォルト 0

秒とマイクロ秒を組み合わせる例:

  • 2秒500ミリ秒 → stream_set_timeout($s, 2, 500000)
  • 500ミリ秒のみ → stream_set_timeout($s, 0, 500000)
  • 5秒ちょうど → stream_set_timeout($s, 5)

返り値

  • 成功時:true
  • 失敗時:false

タイムアウトの検知方法

重要: タイムアウトが発生しても、freadfgets は即座に例外を投げません。処理が終わった後、stream_get_meta_datatimed_out フラグを確認する必要があります。

<?php
$stream = fsockopen('example.com', 80, $errno, $errstr, 5);
stream_set_timeout($stream, 3); // 3秒でタイムアウト

$response = fgets($stream);

// タイムアウトの確認
$meta = stream_get_meta_data($stream);
if ($meta['timed_out']) {
    echo "タイムアウトが発生しました";
}

stream_get_meta_data が返す主なキー:

キー説明
timed_outboolタイムアウトが発生した場合 true
blockedboolブロッキングモードの場合 true
eofboolストリームがEOFに達した場合 true
stream_typestringストリームの種類

基本的な使い方

<?php
// TCP接続して3秒タイムアウトを設定
$stream = fsockopen('example.com', 80, $errno, $errstr, 5);

if (!$stream) {
    die("接続失敗: [{$errno}] {$errstr}");
}

// 読み書きのタイムアウトを3秒に設定
stream_set_timeout($stream, 3);

// HTTPリクエスト送信
fwrite($stream, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");

// レスポンス受信
$response = '';
while (!feof($stream)) {
    $response .= fgets($stream, 4096);

    $meta = stream_get_meta_data($stream);
    if ($meta['timed_out']) {
        echo "タイムアウト発生" . PHP_EOL;
        break;
    }
}

fclose($stream);
echo "受信バイト数: " . strlen($response) . PHP_EOL;

実践例(クラスを使った実装)

例1:タイムアウト付きTCPクライアント

接続・送信・受信のすべての段階でタイムアウトを管理する基本クラスです。

<?php

class TimeoutTcpClient
{
    private $socket   = null;
    private int   $connectTimeout;
    private int   $readTimeout;
    private int   $readTimeoutUsec;

    public function __construct(
        int $connectTimeoutSec = 5,
        int $readTimeoutSec    = 3,
        int $readTimeoutUsec   = 0
    ) {
        $this->connectTimeout  = $connectTimeoutSec;
        $this->readTimeout     = $readTimeoutSec;
        $this->readTimeoutUsec = $readTimeoutUsec;
    }

    public function connect(string $host, int $port): void
    {
        $this->socket = fsockopen(
            $host, $port,
            $errno, $errstr,
            $this->connectTimeout  // 接続タイムアウト
        );

        if (!$this->socket) {
            throw new RuntimeException("接続失敗 [{$errno}]: {$errstr}");
        }

        // 読み書きのタイムアウトを設定
        $result = stream_set_timeout(
            $this->socket,
            $this->readTimeout,
            $this->readTimeoutUsec
        );

        if (!$result) {
            throw new RuntimeException("タイムアウト設定に失敗しました");
        }
    }

    public function send(string $data): int
    {
        $this->assertConnected();
        $written = fwrite($this->socket, $data);

        if ($written === false) {
            throw new RuntimeException("送信失敗");
        }

        return $written;
    }

    public function receive(int $bufferSize = 4096): string
    {
        $this->assertConnected();

        $response = '';

        while (!feof($this->socket)) {
            $chunk = fread($this->socket, $bufferSize);

            if ($chunk === false) {
                break;
            }

            $response .= $chunk;

            $meta = stream_get_meta_data($this->socket);
            if ($meta['timed_out']) {
                throw new RuntimeException(
                    "受信タイムアウト({$this->readTimeout}秒 + {$this->readTimeoutUsec}μs)"
                );
            }
        }

        return $response;
    }

    public function close(): void
    {
        if (is_resource($this->socket)) {
            fclose($this->socket);
            $this->socket = null;
        }
    }

    private function assertConnected(): void
    {
        if (!is_resource($this->socket)) {
            throw new RuntimeException("接続されていません。connect() を先に呼び出してください");
        }
    }
}

// 使用例
$client = new TimeoutTcpClient(connectTimeoutSec: 5, readTimeoutSec: 3);

try {
    $client->connect('example.com', 80);
    $client->send("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
    $response = $client->receive();
    echo "受信完了: " . strlen($response) . " バイト" . PHP_EOL;
} catch (RuntimeException $e) {
    echo "エラー: " . $e->getMessage() . PHP_EOL;
} finally {
    $client->close();
}

出力例:

受信完了: 1256 バイト

例2:タイムアウトを動的に変更しながらフェーズ別に通信する

接続・認証・データ受信など、フェーズごとに異なるタイムアウトを設定するパターンです。

<?php

class PhaseAwareStreamHandler
{
    private $stream;
    private array $phaseLog = [];

    public function __construct(resource $stream)
    {
        $this->stream = $stream;
    }

    /**
     * フェーズ名と秒数を指定してタイムアウトを変更する
     */
    public function enterPhase(string $phaseName, int $seconds, int $microseconds = 0): void
    {
        $result = stream_set_timeout($this->stream, $seconds, $microseconds);

        $timeoutStr = $seconds . '秒';
        if ($microseconds > 0) {
            $timeoutStr .= ' + ' . number_format($microseconds) . 'μs';
        }

        $this->phaseLog[] = [
            'phase'   => $phaseName,
            'timeout' => $timeoutStr,
            'success' => $result,
            'time'    => date('H:i:s'),
        ];

        if (!$result) {
            throw new RuntimeException("フェーズ [{$phaseName}] のタイムアウト設定に失敗");
        }
    }

    public function readLine(): string
    {
        $line = fgets($this->stream);

        $meta = stream_get_meta_data($this->stream);
        if ($meta['timed_out']) {
            $current = end($this->phaseLog);
            throw new RuntimeException(
                "フェーズ [{$current['phase']}] でタイムアウト({$current['timeout']})"
            );
        }

        return $line !== false ? rtrim($line) : '';
    }

    public function write(string $data): void
    {
        if (fwrite($this->stream, $data) === false) {
            throw new RuntimeException("書き込みに失敗しました");
        }
    }

    public function printLog(): void
    {
        echo "=== フェーズログ ===" . PHP_EOL;
        foreach ($this->phaseLog as $entry) {
            $status = $entry['success'] ? '✓' : '✗';
            echo "  [{$entry['time']}] {$status} {$entry['phase']}: タイムアウト {$entry['timeout']}" . PHP_EOL;
        }
    }

    public function getStream(): resource
    {
        return $this->stream;
    }
}

// 使用例(SMTPライクなプロトコルシミュレーション)
try {
    $socket = fsockopen('smtp.example.com', 25, $errno, $errstr, 5);

    if (!$socket) {
        throw new RuntimeException("接続失敗: [{$errno}] {$errstr}");
    }

    $handler = new PhaseAwareStreamHandler($socket);

    // 接続確認:短めのタイムアウト
    $handler->enterPhase('CONNECT', 2);
    $banner = $handler->readLine();

    // EHLO:中程度のタイムアウト
    $handler->enterPhase('EHLO', 5);
    $handler->write("EHLO localhost\r\n");
    $ehloResp = $handler->readLine();

    // DATA転送:長めのタイムアウト
    $handler->enterPhase('DATA', 30);
    // ... データ転送処理 ...

    $handler->printLog();
    fclose($socket);

} catch (RuntimeException $e) {
    echo "エラー: " . $e->getMessage() . PHP_EOL;
}

出力例(接続できた場合):

=== フェーズログ ===
  [12:00:01] ✓ CONNECT: タイムアウト 2秒
  [12:00:01] ✓ EHLO: タイムアウト 5秒
  [12:00:01] ✓ DATA: タイムアウト 30秒

例3:タイムアウトを検知してリトライするHTTPクライアント

タイムアウト発生時に自動リトライするパターンです。指数バックオフで待機時間を伸ばします。

<?php

class RetryableHttpClient
{
    private int   $maxRetries;
    private int   $baseTimeoutSec;
    private float $backoffMultiplier;

    public function __construct(
        int   $maxRetries        = 3,
        int   $baseTimeoutSec    = 3,
        float $backoffMultiplier = 2.0
    ) {
        $this->maxRetries        = $maxRetries;
        $this->baseTimeoutSec    = $baseTimeoutSec;
        $this->backoffMultiplier = $backoffMultiplier;
    }

    public function get(string $host, string $path = '/'): array
    {
        $attempt = 0;
        $lastError = null;

        while ($attempt < $this->maxRetries) {
            $attempt++;

            // リトライごとにタイムアウトを延長
            $timeout = (int) ($this->baseTimeoutSec * ($this->backoffMultiplier ** ($attempt - 1)));

            try {
                $result = $this->doRequest($host, $path, $timeout);
                $result['attempts'] = $attempt;
                return $result;

            } catch (RuntimeException $e) {
                $lastError = $e->getMessage();
                echo "試行 {$attempt}/{$this->maxRetries} 失敗: {$lastError}(タイムアウト: {$timeout}秒)" . PHP_EOL;

                if ($attempt < $this->maxRetries) {
                    sleep(1); // 1秒待ってリトライ
                }
            }
        }

        throw new RuntimeException("最大リトライ回数到達: {$lastError}");
    }

    private function doRequest(string $host, string $path, int $timeoutSec): array
    {
        $socket = fsockopen($host, 80, $errno, $errstr, $timeoutSec);

        if (!$socket) {
            throw new RuntimeException("接続失敗 [{$errno}]: {$errstr}");
        }

        stream_set_timeout($socket, $timeoutSec);

        fwrite($socket, "GET {$path} HTTP/1.0\r\nHost: {$host}\r\n\r\n");

        $response = '';
        while (!feof($socket)) {
            $chunk = fgets($socket, 4096);

            $meta = stream_get_meta_data($socket);
            if ($meta['timed_out']) {
                fclose($socket);
                throw new RuntimeException("タイムアウト発生({$timeoutSec}秒)");
            }

            if ($chunk !== false) {
                $response .= $chunk;
            }
        }

        fclose($socket);

        return [
            'status'        => $this->parseStatus($response),
            'body_bytes'    => strlen($response),
            'timeout_used'  => $timeoutSec,
        ];
    }

    private function parseStatus(string $response): string
    {
        if (preg_match('/^HTTP\/\S+\s+(\d{3}[^\r\n]*)/', $response, $m)) {
            return $m[1];
        }
        return 'unknown';
    }
}

// 使用例
$client = new RetryableHttpClient(maxRetries: 3, baseTimeoutSec: 2);

try {
    $result = $client->get('example.com', '/');
    echo "成功!試行回数: {$result['attempts']}, ステータス: {$result['status']}, バイト数: {$result['body_bytes']}" . PHP_EOL;
} catch (RuntimeException $e) {
    echo "最終エラー: " . $e->getMessage() . PHP_EOL;
}

出力例(1回目で成功した場合):

成功!試行回数: 1, ステータス: 200 OK, バイト数: 1256

出力例(タイムアウトが続いた場合):

試行 1/3 失敗: タイムアウト発生(2秒)(タイムアウト: 2秒)
試行 2/3 失敗: タイムアウト発生(4秒)(タイムアウト: 4秒)
試行 3/3 失敗: タイムアウト発生(8秒)(タイムアウト: 8秒)
最終エラー: 最大リトライ回数到達: タイムアウト発生(8秒)

例4:マイクロ秒単位のタイムアウトで高精度な通信制御

$microseconds パラメータを活用した、ミリ秒・マイクロ秒単位の細かい制御です。

<?php

class PrecisionTimeoutStream
{
    private $stream;
    private array $timeoutHistory = [];

    public function __construct(resource $stream)
    {
        $this->stream = $stream;
    }

    /**
     * 浮動小数点で秒数を指定する(例:1.5 → 1秒500ミリ秒)
     */
    public function setTimeoutFloat(float $seconds): bool
    {
        $sec  = (int) floor($seconds);
        $usec = (int) (($seconds - $sec) * 1_000_000);

        $result = stream_set_timeout($this->stream, $sec, $usec);

        $this->timeoutHistory[] = [
            'seconds'      => $sec,
            'microseconds' => $usec,
            'display'      => $this->formatTimeout($sec, $usec),
            'success'      => $result,
        ];

        return $result;
    }

    /**
     * ミリ秒で指定する
     */
    public function setTimeoutMs(int $milliseconds): bool
    {
        $sec  = (int) floor($milliseconds / 1000);
        $usec = ($milliseconds % 1000) * 1000;

        return $this->setTimeoutRaw($sec, $usec);
    }

    /**
     * 秒・マイクロ秒を直接指定する
     */
    public function setTimeoutRaw(int $seconds, int $microseconds = 0): bool
    {
        $result = stream_set_timeout($this->stream, $seconds, $microseconds);

        $this->timeoutHistory[] = [
            'seconds'      => $seconds,
            'microseconds' => $microseconds,
            'display'      => $this->formatTimeout($seconds, $microseconds),
            'success'      => $result,
        ];

        return $result;
    }

    public function isTimedOut(): bool
    {
        $meta = stream_get_meta_data($this->stream);
        return $meta['timed_out'];
    }

    public function getMeta(): array
    {
        return stream_get_meta_data($this->stream);
    }

    public function printHistory(): void
    {
        echo "=== タイムアウト設定履歴 ===" . PHP_EOL;
        foreach ($this->timeoutHistory as $i => $entry) {
            $status = $entry['success'] ? '✓' : '✗';
            echo "  [{$i}] {$status} {$entry['display']}" . PHP_EOL;
        }
    }

    private function formatTimeout(int $sec, int $usec): string
    {
        $parts = [];
        if ($sec > 0) {
            $parts[] = "{$sec}秒";
        }
        if ($usec >= 1000) {
            $parts[] = ($usec / 1000) . "ミリ秒";
        } elseif ($usec > 0) {
            $parts[] = "{$usec}マイクロ秒";
        }
        return implode(' + ', $parts) ?: '0秒';
    }
}

// 使用例
$socket = fsockopen('example.com', 80, $errno, $errstr, 5);

if ($socket) {
    $pts = new PrecisionTimeoutStream($socket);

    $pts->setTimeoutFloat(1.5);    // 1.5秒
    $pts->setTimeoutMs(750);       // 750ミリ秒
    $pts->setTimeoutRaw(0, 250000); // 250ミリ秒

    $pts->printHistory();

    // 最後に設定した250msで通信
    fwrite($socket, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
    $line = fgets($socket);
    echo PHP_EOL . "タイムアウト発生: " . ($pts->isTimedOut() ? 'はい' : 'いいえ') . PHP_EOL;
    echo "レスポンス先頭: " . trim($line) . PHP_EOL;

    fclose($socket);
}

出力例:

=== タイムアウト設定履歴 ===
  [0] ✓ 1秒 + 500ミリ秒
  [1] ✓ 750ミリ秒
  [2] ✓ 250ミリ秒

タイムアウト発生: いいえ
レスポンス先頭: HTTP/1.0 200 OK

例5:stream_get_meta_data でタイムアウト状態を詳細モニタリングする

ストリームの状態を継続的に記録し、タイムアウト・EOF・ブロッキング状態を一元管理します。

<?php

class StreamHealthMonitor
{
    private $stream;
    private string $name;
    private array  $snapshots = [];

    public function __construct(resource $stream, string $name = 'stream')
    {
        $this->stream = $stream;
        $this->name   = $name;
    }

    public function setTimeout(int $seconds, int $microseconds = 0): bool
    {
        return stream_set_timeout($this->stream, $seconds, $microseconds);
    }

    /**
     * 現在のストリーム状態をスナップショットとして記録する
     */
    public function snapshot(string $label = ''): array
    {
        $meta = stream_get_meta_data($this->stream);

        $snap = [
            'label'       => $label,
            'time'        => date('H:i:s'),
            'timed_out'   => $meta['timed_out'],
            'blocked'     => $meta['blocked'],
            'eof'         => $meta['eof'],
            'stream_type' => $meta['stream_type'],
            'mode'        => $meta['mode'],
        ];

        $this->snapshots[] = $snap;
        return $snap;
    }

    public function readWithMonitoring(int $bufferSize = 4096): string
    {
        $data = '';

        while (!feof($this->stream)) {
            $chunk = fread($this->stream, $bufferSize);

            $snap = $this->snapshot("fread後");

            if ($snap['timed_out']) {
                throw new RuntimeException("[{$this->name}] タイムアウト検知({$snap['time']})");
            }

            if ($chunk !== false && $chunk !== '') {
                $data .= $chunk;
            }
        }

        $this->snapshot("EOF到達");
        return $data;
    }

    public function printReport(): void
    {
        echo "=== ストリーム [{$this->name}] 状態レポート ===" . PHP_EOL;
        echo str_pad("ラベル",        16)
           . str_pad("時刻",          10)
           . str_pad("TimedOut",      12)
           . str_pad("Blocked",       10)
           . "EOF" . PHP_EOL;
        echo str_repeat('-', 54) . PHP_EOL;

        foreach ($this->snapshots as $s) {
            echo str_pad($s['label'],                   16)
               . str_pad($s['time'],                    10)
               . str_pad($s['timed_out'] ? 'true' : 'false', 12)
               . str_pad($s['blocked']   ? 'true' : 'false', 10)
               . ($s['eof'] ? 'true' : 'false') . PHP_EOL;
        }
    }
}

// 使用例
$socket = fsockopen('example.com', 80, $errno, $errstr, 5);

if ($socket) {
    $monitor = new StreamHealthMonitor($socket, 'example.com:80');
    $monitor->setTimeout(5);

    fwrite($socket, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");

    try {
        $body = $monitor->readWithMonitoring();
        echo "受信: " . strlen($body) . " バイト" . PHP_EOL . PHP_EOL;
    } catch (RuntimeException $e) {
        echo "エラー: " . $e->getMessage() . PHP_EOL . PHP_EOL;
    }

    $monitor->printReport();
    fclose($socket);
}

出力例:

受信: 1256 バイト

=== ストリーム [example.com:80] 状態レポート ===
ラベル          時刻       TimedOut    Blocked   EOF
------------------------------------------------------
fread後         12:00:01   false       true      false
EOF到達         12:00:01   false       true      true

例6:ファイルストリームへの適用と注意点を示すデモ

stream_set_timeout はネットワークストリームに対して効果的ですが、ローカルファイルでの動作の違いも把握しておくことが重要です。

<?php

class StreamTimeoutDemo
{
    /**
     * 各ストリームタイプでタイムアウト設定を試みる
     */
    public static function runAll(): void
    {
        $cases = [
            'ローカルファイル'      => fn() => fopen('php://temp', 'r+'),
            'メモリストリーム'      => fn() => fopen('php://memory', 'r+'),
            'stdin(標準入力)'     => fn() => fopen('php://stdin', 'r'),
            'HTTPストリーム'        => fn() => @fopen('https://example.com', 'r'),
        ];

        echo str_pad("ストリーム種別", 24) . str_pad("設定結果", 12) . "timed_out初期値" . PHP_EOL;
        echo str_repeat('-', 52) . PHP_EOL;

        foreach ($cases as $label => $factory) {
            $stream = $factory();
            if (!is_resource($stream)) {
                echo str_pad($label, 24) . "開けませんでした" . PHP_EOL;
                continue;
            }

            $result = stream_set_timeout($stream, 1);
            $meta   = stream_get_meta_data($stream);
            $status = $result ? '✓ 成功' : '✗ 失敗';

            echo str_pad($label, 24)
               . str_pad($status, 12)
               . ($meta['timed_out'] ? 'true' : 'false') . PHP_EOL;

            fclose($stream);
        }

        echo PHP_EOL;
        echo "【注意】ローカルファイル・メモリストリームでは" . PHP_EOL;
        echo "  set_timeout は成功しますが、実際にタイムアウトは" . PHP_EOL;
        echo "  発生しません(常にデータが即座に読めるため)。" . PHP_EOL;
        echo "  タイムアウト制御はネットワーク・ソケット系ストリームで使ってください。" . PHP_EOL;
    }
}

StreamTimeoutDemo::runAll();

出力例:

ストリーム種別          設定結果    timed_out初期値
----------------------------------------------------
ローカルファイル        ✓ 成功      false
メモリストリーム        ✓ 成功      false
stdin(標準入力)       ✓ 成功      false
HTTPストリーム          ✓ 成功      false

【注意】ローカルファイル・メモリストリームでは
  set_timeout は成功しますが、実際にタイムアウトは
  発生しません(常にデータが即座に読めるため)。
  タイムアウト制御はネットワーク・ソケット系ストリームで使ってください。

関連する関数との比較

関数役割返り値
stream_set_timeout読み書きのタイムアウトを設定bool
stream_get_meta_dataタイムアウト発生を検知(timed_out キー)array
stream_set_blockingブロッキング/ノンブロッキングの切り替えbool
stream_set_read_buffer読み取りバッファサイズを設定int(0=成功)
fsockopenソケット接続(第5引数が接続タイムアウト)resource|false
stream_context_createhttp ラッパーのタイムアウトを timeout オプションで設定resource

fsockopen の接続タイムアウトとの違い

// fsockopen の第5引数 → 接続確立までのタイムアウト
$socket = fsockopen('example.com', 80, $errno, $errstr, 5.0);
//                                                       ↑ 接続タイムアウト(秒)

// stream_set_timeout → 接続後の読み書きのタイムアウト
stream_set_timeout($socket, 3);
//                           ↑ 読み書きタイムアウト(秒)
観点fsockopen 第5引数stream_set_timeout
適用タイミングTCP接続確立まで接続後の読み書き
設定後の変更不可いつでも変更可能
タイムアウト検知戻り値 falsestream_get_meta_data

よくある注意点・落とし穴

1. タイムアウトは stream_get_meta_data で確認する

タイムアウト発生時に例外は投げられません。必ずメタデータを確認します。

// NG:タイムアウトに気づかずループが終わる
while (!feof($stream)) {
    $data .= fread($stream, 4096);
}

// OK:タイムアウトを毎回チェックする
while (!feof($stream)) {
    $chunk = fread($stream, 4096);
    $meta  = stream_get_meta_data($stream);
    if ($meta['timed_out']) {
        throw new RuntimeException("タイムアウト");
    }
    $data .= $chunk;
}

2. ローカルファイルへの効果は限定的

ローカルファイルやメモリストリームは即座にデータが読めるため、タイムアウトが実際に発生することはありません。主にネットワークソケットや標準入力で利用します。

3. $microseconds には 999999 以下の値を指定する

$microseconds は0〜999999の範囲(1秒未満)です。1,000,000以上を渡した場合の動作は未定義です。

// NG
stream_set_timeout($s, 0, 1_500_000); // 1,500,000μs は未定義

// OK:秒とマイクロ秒に分解する
stream_set_timeout($s, 1, 500_000);   // 1秒500ミリ秒

4. stream_set_timeout は socket_set_timeout の別名

socket_set_timeoutstream_set_timeout の古い別名です。現在は stream_set_timeout を使うことが推奨されています。

// 古い書き方(PHP 8でも動くが非推奨)
socket_set_timeout($stream, 3);

// 推奨
stream_set_timeout($stream, 3);

まとめ

項目内容
関数名stream_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool
主な用途ネットワーク・ソケットストリームの読み書きタイムアウト設定
タイムアウト検知stream_get_meta_data($stream)['timed_out'] で確認
返り値true = 成功、false = 失敗
注意点タイムアウト発生は自動検知されない、ローカルファイルは非効果
PHP バージョンPHP 4.3.0 以上

stream_set_timeout は、ネットワーク通信の安全性を高めるために欠かせない関数です。設定するだけでなく stream_get_meta_data でタイムアウトを明示的に検知する実装が重要です。

fsockopen の接続タイムアウトと組み合わせ、さらにリトライ処理も加えることで、現実の不安定なネットワーク環境にも耐えられる堅牢な通信処理を構築できます。

タイトルとURLをコピーしました