Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】STREAM_SERVER_LISTEN定数の使い方

STREAM_SERVER_LISTEN定数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

STREAM_SERVER_LISTEN定数は、PHPのネットワーク通信機能であるストリームサーバーにおいて、ソケットがクライアントからの接続を待機する、すなわち「リスン」状態であることを示すためのオプションを表す定数です。この定数は主に、ネットワーク上でサーバーアプリケーションを構築する際に使用されるstream_socket_server()関数などの引数に渡されます。

具体的には、stream_socket_server()関数でサーバーソケットを作成する際、flags引数にSTREAM_SERVER_LISTEN定数を指定することで、そのソケットが接続待ち状態として設定されることを明示します。これにより、作成されたソケットは指定されたアドレスとポートでクライアントからの接続要求を能動的に待ち受け、受け入れられる準備が整います。

PHP 8の環境下で、この定数はサーバーソケットの動作を正確に制御するために利用されます。ネットワークプログラミングにおいて、サーバーがクライアントからの接続を適切に待ち受けることはサービスの安定稼働に不可欠であり、STREAM_SERVER_LISTEN定数はそのようなソケットの基本的な役割を設定するための重要なフラグの一つです。他のストリームサーバー関連のオプション定数と組み合わせて使用することで、より詳細なサーバーソケットの挙動を定義することが可能になります。

構文(syntax)

1<?php
2$context = stream_context_create();
3$socket = stream_socket_server("tcp://127.0.0.1:8000", $errno, $errstr, STREAM_SERVER_LISTEN, $context);
4if (!$socket) {
5    echo "$errstr ($errno)\n";
6} else {
7    fclose($socket);
8}
9?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHPでサーバーソケットを作成し、接続を待ち受ける

1<?php
2
3/**
4 * 指定されたアドレスでサーバーソケットを作成し、クライアントからの接続を待ち受けます。
5 * 接続されたクライアントにメッセージを送信し、クライアントからのメッセージを受信します。
6 *
7 * @param string $address サーバーがリッスンするアドレス (例: 'tcp://127.0.0.1:8000')
8 * @return void
9 */
10function createAndListenServerSocket(string $address): void
11{
12    // stream_socket_server() は、サーバーサイドのソケットを作成します。
13    // STREAM_SERVER_LISTEN フラグは、ソケットをバインドし、接続を待ち受ける状態にするよう指定します。
14    $serverSocket = stream_socket_server($address, $errno, $errstr, STREAM_SERVER_LISTEN);
15
16    if (false === $serverSocket) {
17        echo "サーバーの作成に失敗しました: ($errno) $errstr\n";
18        return;
19    }
20
21    echo "PHPサーバーが {$address} で起動しました。クライアントからの接続を待機中...\n";
22
23    // サーバーが停止するまで、無限ループでクライアントからの接続を受け入れ続けます。
24    while (true) {
25        // stream_socket_accept() は、クライアントからの接続をブロックして待ちます。
26        // 接続が確立されると、そのクライアントとの通信に使用する新しいソケットリソースを返します。
27        $clientSocket = stream_socket_accept($serverSocket);
28
29        if (false === $clientSocket) {
30            echo "クライアント接続の受け入れに失敗しました。\n";
31            continue;
32        }
33
34        echo "クライアントが接続しました。\n";
35
36        // 接続されたクライアントにメッセージを送信します。
37        fwrite($clientSocket, "Hello from PHP server! Please send me a message.\n");
38
39        // クライアントからのメッセージを読み込みます。
40        $message = fread($clientSocket, 1024); // 最大1024バイトを読み込みます。
41        echo "クライアントからメッセージを受信: " . trim($message) . "\n";
42
43        // クライアントソケットを閉じ、このクライアントとの接続を終了します。
44        fclose($clientSocket);
45        echo "クライアントとの接続を閉じました。\n";
46    }
47
48    // 通常、上記の無限ループのためこの部分は実行されませんが、
49    // サーバーシャットダウン時にはメインソケットも閉じるべきです。
50    // fclose($serverSocket);
51}
52
53// サーバーがリッスンするアドレスを指定します (ローカルホストのポート8000)。
54$serverAddress = 'tcp://127.0.0.1:8000';
55
56// サーバーの起動関数を実行します。
57createAndListenServerSocket($serverAddress);
58
59?>

このPHPコードは、TCP/IPプロトコルを利用してシンプルなサーバーを構築し、指定されたネットワークアドレスでクライアントからの接続を待ち受ける方法をシステムエンジニアを目指す初心者向けに示しています。

中心となるcreateAndListenServerSocket関数は、引数$addressで受け取ったネットワークアドレス(例: tcp://127.0.0.1:8000)に基づき、サーバーソケットを初期化します。ここで重要な役割を果たすのが、stream_socket_server()関数です。この関数はサーバー側のソケットを作成し、その第4引数にSTREAM_SERVER_LISTENという定数を指定することで、ソケットをネットワークアドレスにバインドし、クライアントからの接続を受け入れる準備ができた「リッスン(待ち受け)」状態にするよう指示します。STREAM_SERVER_LISTEN定数自体は引数を取らず、特定の値を戻り値として持ちませんが、stream_socket_server関数の挙動を制御するフラグとして機能します。

サーバーが起動すると、無限ループに入り、stream_socket_accept()関数を使ってクライアントからの接続をブロックして待ちます。接続が確立されると、通信に使用するための新しいソケットリソースが返されます。このリソースを通じて、fwrite()でクライアントへメッセージを送信し、fread()でクライアントからのメッセージを受信します。通信終了後はfclose()でクライアントソケットを閉じ、次の接続を待ちます。これにより、複数のクライアント接続を順次処理することが可能です。エラーが発生した際には、適切なメッセージが表示され、処理が継続または終了します。

このコードは、PHPで基本的なサーバーソケットを構築する例です。STREAM_SERVER_LISTENフラグは、stream_socket_server関数でソケットを作成し、クライアントからの接続を待ち受ける状態にするために非常に重要です。サーバーの作成やクライアント接続の受け入れが失敗した場合のエラーハンドリングは、問題特定に不可欠ですので、適切に実装してください。while (true)による無限ループは、サーバーを停止させる仕組みや、複数のクライアントを同時に処理する方法(非同期処理やマルチプロセスなど)を本番環境で実装する際に考慮が必要です。また、使用後のクライアントソケットやサーバーソケットは、fclose()で適切にリソースを解放することを忘れないでください。

PHPでstream_socket_clientを使うTCP通信

1<?php
2
3/**
4 * 簡易TCPソケットサーバーとクライアントの通信例。
5 * STREAM_SERVER_LISTEN 定数と stream_socket_client 関数を組み合わせて使用します。
6 *
7 * このスクリプトは、サーバーを非ブロッキングモードで起動し、短時間だけ接続を待ちます。
8 * その後、クライアントがサーバーに接続し、メッセージを交換します。
9 * 通常、サーバーとクライアントは別々のプロセスとして実行されますが、
10 * この例では単一ファイルで両方の動作を示します。
11 */
12
13// サーバーとクライアントが通信するポートとホスト
14const SERVER_PORT = 12345;
15const SERVER_HOST = '127.0.0.1';
16const SERVER_ADDRESS = 'tcp://' . SERVER_HOST . ':' . SERVER_PORT;
17
18/**
19 * 簡易TCPソケットサーバーを起動し、単一のクライアント接続を処理します。
20 *
21 * @param int $timeout サーバーが接続を待つ最大秒数。
22 * @return void
23 */
24function startSocketServer(int $timeout = 2): void
25{
26    // stream_socket_server を使用してソケットサーバーを作成します。
27    // STREAM_SERVER_BIND: アドレスとポートにソケットをバインドするために必要です。
28    // STREAM_SERVER_LISTEN: ソケットがクライアントからの接続を受け付ける状態であることを示します。
29    //                      このフラグは通常デフォルトで有効ですが、明示的に指定することで意図を明確にできます。
30    $server = @stream_socket_server(
31        SERVER_ADDRESS,
32        $errno,
33        $errstr,
34        STREAM_SERVER_BIND | STREAM_SERVER_LISTEN
35    );
36
37    if (!$server) {
38        echo "サーバーの起動に失敗しました: ($errno) $errstr\n";
39        return;
40    }
41
42    echo "サーバーが " . SERVER_ADDRESS . " でリッスンを開始しました。\n";
43
44    // サーバーソケットを非ブロッキングモードに設定します。
45    // これにより、stream_socket_accept が接続を待っている間も、
46    // スクリプトの他の部分(この場合、startSocketClient関数)が実行可能になります。
47    stream_set_blocking($server, false);
48
49    $endTime = microtime(true) + $timeout;
50    $clientSocket = null;
51
52    // 指定されたタイムアウト時間までクライアントからの接続を待機します。
53    while (microtime(true) < $endTime) {
54        // stream_socket_accept は新しい接続がある場合にクライアントソケットを返します。
55        // 非ブロッキングモードでは、接続がない場合すぐに false を返します。
56        $clientSocket = @stream_socket_accept($server, 0); // タイムアウト0で非ブロッキング
57        if ($clientSocket) {
58            echo "サーバー: クライアントが接続しました。\n";
59            break;
60        }
61        usleep(100000); // 100ミリ秒待機してCPU負荷を軽減
62    }
63
64    if ($clientSocket) {
65        $message = fread($clientSocket, 1024); // クライアントからのメッセージを読み込む
66        echo "サーバー: クライアントからメッセージを受信: " . trim($message) . "\n";
67
68        $response = "サーバーからの応答: " . strtoupper($message);
69        fwrite($clientSocket, $response); // クライアントに応答を送信
70        echo "サーバー: クライアントに応答を送信: " . trim($response) . "\n";
71        fclose($clientSocket);
72    } else {
73        echo "サーバー: 指定時間内にクライアントからの接続がありませんでした。\n";
74    }
75
76    fclose($server);
77    echo "サーバーが終了しました。\n";
78}
79
80/**
81 * 簡易TCPソケットクライアントとしてサーバーに接続し、メッセージを送受信します。
82 *
83 * @param string $message サーバーに送信するメッセージ。
84 * @param int $timeout サーバーへの接続を待つ最大秒数。
85 * @return void
86 */
87function startSocketClient(string $message, int $timeout = 1): void
88{
89    echo "クライアント: " . SERVER_ADDRESS . " への接続を試みます。\n";
90
91    // stream_socket_client を使用してサーバーに接続します。
92    // STREAM_CLIENT_CONNECT: 接続モードであることを示します (デフォルト動作)。
93    $client = @stream_socket_client(
94        SERVER_ADDRESS,
95        $errno,
96        $errstr,
97        $timeout,
98        STREAM_CLIENT_CONNECT
99    );
100
101    if (!$client) {
102        echo "クライアント: サーバーへの接続に失敗しました: ($errno) $errstr\n";
103        return;
104    }
105
106    echo "クライアント: サーバーに接続しました。\n";
107
108    fwrite($client, $message); // サーバーにメッセージを送信
109    echo "クライアント: サーバーにメッセージを送信: " . trim($message) . "\n";
110
111    $response = fread($client, 1024); // サーバーからの応答を読み込む
112    echo "クライアント: サーバーから応答を受信: " . trim($response) . "\n";
113
114    fclose($client);
115    echo "クライアント: 接続を閉じました。\n";
116}
117
118// ==========================================================
119// メイン処理: サーバーとクライアントをこの単一スクリプト内で順次実行します。
120//
121// 注意点:
122// 1. startSocketServer 関数が先に呼び出され、非ブロッキングで接続待機を開始します。
123// 2. その後、startSocketClient 関数がサーバーへの接続を試みます。
124// 3. サーバーの待機時間内にクライアントが接続できれば、通信が成功します。
125//    ポートが利用可能であることを確認してください。
126// ==========================================================
127
128// サーバーを起動し、クライアントからの接続を2秒間待機します。
129startSocketServer(2);
130
131// クライアントを起動し、サーバーにメッセージを送信します。
132// サーバーがすでにリッスンを開始していることを期待します。
133startSocketClient("Hello from Client!");
134
135?>

このPHPコードは、STREAM_SERVER_LISTEN定数とstream_socket_client関数を使用して、簡易的なTCPソケットサーバーとクライアントの通信を実演しています。STREAM_SERVER_LISTENは、サーバー側でソケットを作成するstream_socket_server関数に渡されるフラグの一つで、ソケットがクライアントからの接続を受け付ける「リッスン」状態になることを明示します。この定数自体には引数や戻り値はありませんが、stream_socket_server関数に組み合わせて使うことで、サーバーは特定のポートで接続を待ち受けられるようになります。一方、stream_socket_client関数は、クライアント側から指定されたサーバーアドレスとポートに接続を開始するために使用されます。引数には、接続先のアドレス、エラー番号とメッセージを受け取る変数、接続試行のタイムアウト時間、そして接続の種類(通常はSTREAM_CLIENT_CONNECT)を指定します。この関数は、接続が成功するとクライアントソケットのストリームリソースを、失敗するとfalseを戻り値として返します。サンプルコードでは、サーバーが非ブロッキングモードでクライアントの接続を待ち、クライアントが接続を試みて、互いにメッセージを送受信する基本的なソケット通信の流れを示しており、システム間のデータ連携の基礎を学ぶのに役立ちます。

このサンプルコードは、TCPサーバーとクライアントの通信を一つのスクリプト内で順次実行する特別な例です。サーバーが非ブロッキングモードで短時間接続を待つ間に、クライアントが接続を試みるため、実行のタイミングとポートの利用可能性が重要になります。指定されたポート番号が他のプログラムで使用されていないことを確認してください。STREAM_SERVER_LISTEN定数は、サーバーが接続を受け付ける状態を示すために使用され、STREAM_SERVER_BINDと組み合わせて用いることが一般的です。実際のシステムでは、サーバーとクライアントは通常別々のプロセスで動作します。また、本番環境ではエラー抑制演算子@の使用を避け、詳細なエラーメッセージを基に問題解決を行うようにしましょう。

関連コンテンツ

関連IT用語

関連プログラミング言語