現在の位置: ホーム> 最新記事一覧> socket_accept()は、socket_set_timeoutと協力して接続タイムアウト制御を実装します

socket_accept()は、socket_set_timeoutと協力して接続タイムアウト制御を実装します

M66 2025-05-28

PHPでは、ネイティブソケットを使用してプログラミングする場合、 socket_accept()関数はクライアント接続要求を受け入れるために使用されますが、デフォルトでは、この関数はブロックしています。つまり、クライアント接続がない場合、プログラムは待機し、自動的にタイムアウトできません。接続を待つためにプログラムが行き詰まったり反応したりしないようにするために、 socket_set_timeout()を組み合わせて接続タイムアウト制御を実現し、それによりプログラムの堅牢性を改善できます。

この記事では、socket_accept()socket_set_timeout()を使用して、php接続タイムアウト制御の関数を実装する方法を詳細に紹介します。

1。基本的な知識のレビュー

  • socket_accept($ socket)
    クライアント接続リクエストのブロックを待っています。接続要求がある場合、新しいソケットリソースが返されます。それ以外の場合はブロックされます。

  • socket_set_timeout($ socket、$ seconds、$ microseconds)
    指定されたソケットのタイムアウト時間を設定します。タイムアウト後、読み取り/書き込み操作はタイムアウトエラーを返します。

socket_set_timeout()は、読み取りおよび書き込み操作のタイムアウト制御であり、 socket_accept()のブロッキング待機時間を直接制御できないことに注意してください。したがって、他の方法(非ブロッキングモードやsocket_select()を使用するなど)と協力して、真の接続待機タイムアウトを達成する必要があります。

2。実装のアイデア

  1. リスニングソケットを非ブロッキングモードに設定します<br> この方法でsocket_accept()を呼び出してもブロックされません。接続要求がない場合、 Falseはすぐに返されます。

  2. ループ +遅延を使用して、タイムアウト<br>を判断します ループでsocket_accept()を繰り返し呼び出します。 falseが返された場合は、タイムアウトがタイムアウトされているかどうかを判断します。タイムアウトがタイムアウトされている場合、待機は終了します。

  3. 接続が受信されたら、 socket_set_timeout()を使用して読み取りおよび書き込みタイムアウト<br>を設定します 後続のデータ送信中にタイムアウト制御があることを確認してください。

3。サンプルコード

<?php
$host = "0.0.0.0";
$port = 12345;
$timeoutSeconds = 10; // 最大待機接続時間

// 作成する TCP socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
    die("socket_create failed: " . socket_strerror(socket_last_error()) . "\n");
}

// バインドポート
if (socket_bind($socket, $host, $port) === false) {
    die("socket_bind failed: " . socket_strerror(socket_last_error($socket)) . "\n");
}

// ポートを聞いてください
if (socket_listen($socket, 5) === false) {
    die("socket_listen failed: " . socket_strerror(socket_last_error($socket)) . "\n");
}

// 監視をセットアップします socket ブロックしていません
socket_set_nonblock($socket);

$startTime = time();
$clientSocket = false;

echo "クライアント接続を待っています,タイムアウト:{$timeoutSeconds}2番\n";

while (true) {
    $clientSocket = @socket_accept($socket);
    if ($clientSocket !== false) {
        echo "クライアントが接続されています!\n";
        break;
    }

    // タイムアウトがあるかどうかを判断します
    if ((time() - $startTime) >= $timeoutSeconds) {
        echo "クライアント接続を待っています超时。\n";
        break;
    }

    // 寝る 100ms 避ける CPU 占有が高すぎる
    usleep(100000);
}

if ($clientSocket !== false) {
    // クライアントのセットアップ socket 読み取りと書き込みタイムアウト,例えば 5 2番
    socket_set_option($clientSocket, SOL_SOCKET, SO_RCVTIMEO, ["sec"=>5, "usec"=>0]);
    socket_set_option($clientSocket, SOL_SOCKET, SO_SNDTIMEO, ["sec"=>5, "usec"=>0]);

    // クライアントデータを読む例
    $buf = '';
    $bytes = socket_recv($clientSocket, $buf, 2048, 0);
    if ($bytes === false) {
        echo "データの受信に失敗したか、タイミングを出しました:" . socket_strerror(socket_last_error($clientSocket)) . "\n";
    } else {
        echo "クライアントデータを受信しました:" . $buf . "\n";
    }

    socket_close($clientSocket);
}

socket_close($socket);
?>

4。コード分析

  • ノンブロッキングリスニングsocket_set_nonblock()を使用してsocket_accept()ブロッキングを回避し、タイムアウトロジックをカスタマイズできるようにします。

  • 接続を待つためにループsocket_accept()が呼び出されるたびに、接続がない場合、すぐにfalseを返し、タイムアウト条件に達するかどうかを判断します。タイムアウトが期限切れにならない場合は、待ち続けてください。

  • 接続後に読み取りと書き込みのタイムアウトを設定しますsocket_set_option()を使用して、クライアントソケットの読み取りと書き込みタイムアウトを設定して、後続のデータが読み取られたときに永続的なブロックを防ぎます。

  • USLEEP()CPUの使用量を減らす:空のループを避けて、過度のCPU使用量を引き起こします。

5。概要

リスニングソケットを非ブロッキングに設定し、ループポーリングを組み合わせて時間を決定することにより、 Socket_Accept()ブロッキング待機接続のタイムアウト制御が達成されます。同時に、接続を受信した後、 socket_set_option()を使用して読み取りおよび書き込みタイムアウトを設定して、データ送信プロセスの安定性とセキュリティを確保します。

このソリューションはシンプルで実用的であり、ソケット接続タイムアウトの手動管理を必要とするPHPサーバープログラムに非常に適しています。