PHP Socket Programming Handbook 読書メモ 1プロセスで複数のクライアントを処理する

php_socket_programming_handbook


1プロセスで複数のクライアントを処理する

  • いくつかの方法がある
    • 複数のプロセスを使用する(UNIX系でのみ使用可能)
    • stream_selectを使用する(全てのOSで動作する)

実装

https://github.com/phpsphb/book-examples/blob/master/multi-connect/listing2.php

<?php

$server = @stream_socket_server('tcp://0.0.0.0:9000', $errno, $errstr);
stream_set_blocking($server, 0);

if (false === $server) {
    fwrite(STDERR, "Error connecting to socket: $errno: $errstr\n");
    exit(1);
}

$connections = [];
$buffers = [];

for (;;) {
    $readable = $connections;
    array_unshift($readable, $server);
    $writable = $connections;
    $except = null;

    if (stream_select($readable, $writable, $except, 0, 500) > 0) {
        // Some streams have data to read
        foreach ((array) $readable as $stream) {
            // When the server is readable this means that a client
            // connection is available. Let's accept the connection and store it
            if ($stream === $server) {
                $client = @stream_socket_accept($stream, 0, $clientAddress);
                $key = (int) $client;
                if (is_resource($client)) {
                    printf("Client %s connected\n", $clientAddress);
                    stream_set_blocking($client, 0);
                    $connections[$key] = $client;
                }
            } else {
                // One of the clients sent data, read it in a client specific buffer
                $key = (int) $stream;

                if (!isset($buffers[$key])) {
                    $buffers[$key] = '';
                }

                $buffers[$key] .= fread($stream, 4096);
            }
        }

        // Some streams are waiting for data
        foreach ((array) $writable as $stream) {
            $key = (int) $stream;

            // Try to write 4096 bytes, look how many bytes were really written,
            // and subtract the written bytes from this client's buffer
            if (isset($buffers[$key]) && strlen($buffers[$key]) > 0) {
                $bytesWritten = fwrite($stream, $buffers[$key], 4096);
                $buffers[$key] = substr($buffers[$key], $bytesWritten);
            }
        }

        // Out of band data, usually not handled.
        foreach ((array) $except as $stream) {
            // Can't happen, we haven't set $except to anything
        }
    }

    // House keeping
    // Purge connections which were closed by the peer
    foreach ($connections as $key => $conn) {
        if (feof($conn)) {
            printf("Client %s closed the connection\n", stream_socket_get_name($conn, true));
            unset($connections[$key]);
            fclose($conn);
        }
    }
}
  • stream_set_blocking($server, 0) でサーバがノンブロッキングモードになる
  • stream_select ストリームに対して動作するselect(2)

コメントをどうぞ

コメントを残す