【PHP8.x】stream_socket_pair()関数の使い方
stream_socket_pair関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
stream_socket_pair関数は、同一ホスト上のプロセス間で双方向通信が可能なソケットのペアを作成する関数です。この関数は、主に親プロセスと子プロセスの間でデータを安全かつ効率的にやり取りするプロセス間通信(IPC: Inter-Process Communication)のメカニズムとして利用されます。
実行されると、互いに接続された2つのストリームリソースを生成し、これらを要素として持つ配列を返します。この配列の各要素は、それぞれが独立したソケットストリームとして機能し、一方に書き込まれたデータはもう一方から読み出すことができます。これにより、双方向のデータの送受信が実現されます。
引数として、ソケットのドメイン(例: UNIXドメイン)、タイプ(例: ストリームソケット)、プロトコルを指定することで、作成されるソケットペアの特性を定義します。成功した場合は2つのストリームリソースを含む配列を返し、失敗した場合はfalseを返します。返されたストリームリソースは、fread()やfwrite()といった標準的なPHPのストリーム関数を用いて、データの読み書きを行うことができます。
構文(syntax)
1stream_socket_pair(int $domain, int $type, int $protocol): array|false
引数(parameters)
int $domain, int $type, int $protocol
- int $domain: 作成するソケットのドメインを指定する整数 (例: AF_UNIX、AF_INET)。
- int $type: 作成するソケットのタイプを指定する整数 (例: SOCK_STREAM、SOCK_DGRAM)。
- int $protocol: 作成するソケットのプロトコルを指定する整数 (通常は0)。
戻り値(return)
array|false
配列または false が返されます。成功した場合、配列の最初の要素には読み取り用のソケット、2 番目の要素には書き込み用のソケットが含まれます。失敗した場合は false が返されます。
サンプルコード
PHP stream_socket_pair でプロセス間通信する
1<?php 2 3/** 4 * stream_socket_pair 関数の基本的な使い方をデモンストレーションします。 5 * この関数は、互いに接続された2つの双方向ソケットを作成します。 6 * 主にプロセス間通信(IPC)に使用されますが、ここでは単一プロセス内での相互通信を示します。 7 * 8 * @return void 9 */ 10function demonstrateStreamSocketPair(): void 11{ 12 echo "stream_socket_pair のデモンストレーションを開始します。\n\n"; 13 14 // AF_UNIX ドメイン: ローカルのプロセス間通信に適しています。 15 // SOCK_STREAM タイプ: 信頼性のある、接続指向の双方向通信を提供します(TCPと同様)。 16 // プロトコル 0: システムが適切なプロトコルを自動選択します。 17 // stream_socket_pair は2つのソケットリソースを要素とする配列、または失敗時に false を返します。 18 $sockets = stream_socket_pair(AF_UNIX, SOCK_STREAM, 0); 19 20 if ($sockets === false) { 21 echo "エラー: ソケットペアの作成に失敗しました。\n"; 22 return; 23 } 24 25 // $sockets[0] と $sockets[1] は互いに接続されたソケットです。 26 // どちらからでも読み書きが可能です。 27 $socketA = $sockets[0]; 28 $socketB = $sockets[1]; 29 30 echo "ソケットペアが正常に作成されました。\n"; 31 echo "ソケットAとソケットBが接続されました。\n\n"; 32 33 // --- ソケットAからソケットBへメッセージを送信 --- 34 $messageFromA = "ソケットAからソケットBへ: こんにちは!"; 35 echo "ソケットAからメッセージを送信します: \"{$messageFromA}\"\n"; 36 $bytesWritten = fwrite($socketA, $messageFromA); 37 38 if ($bytesWritten === false) { 39 echo "エラー: ソケットAからの書き込みに失敗しました。\n"; 40 fclose($socketA); 41 fclose($socketB); 42 return; 43 } 44 echo "ソケットAから {$bytesWritten} バイト書き込みました。\n\n"; 45 46 // --- ソケットBでソケットAからのメッセージを受信 --- 47 // fread は指定されたバイト数まで読み込みます。 48 $readMessageB = fread($socketB, 1024); 49 50 if ($readMessageB === false) { 51 echo "エラー: ソケットBからの読み込みに失敗しました。\n"; 52 fclose($socketA); 53 fclose($socketB); 54 return; 55 } 56 echo "ソケットBでメッセージを受信しました: \"{$readMessageB}\"\n\n"; 57 58 // --- ソケットBからソケットAへ返信を送信 --- 59 $messageFromB = "ソケットBからソケットAへ: どうも、Aさん!"; 60 echo "ソケットBからメッセージを送信します: \"{$messageFromB}\"\n"; 61 $bytesWritten = fwrite($socketB, $messageFromB); 62 63 if ($bytesWritten === false) { 64 echo "エラー: ソケットBからの書き込みに失敗しました。\n"; 65 fclose($socketA); 66 fclose($socketB); 67 return; 68 } 69 echo "ソケットBから {$bytesWritten} バイト書き込みました。\n\n"; 70 71 // --- ソケットAでソケットBからの返信を受信 --- 72 $readMessageA = fread($socketA, 1024); 73 74 if ($readMessageA === false) { 75 echo "エラー: ソケットAからの読み込みに失敗しました。\n"; 76 fclose($socketA); 77 fclose($socketB); 78 return; 79 } 80 echo "ソケットAでメッセージを受信しました: \"{$readMessageA}\"\n\n"; 81 82 // 使用後のソケットリソースは必ず閉じます。 83 fclose($socketA); 84 fclose($socketB); 85 echo "ソケットが閉じられました。デモンストレーションを終了します。\n"; 86} 87 88// 関数を実行してデモンストレーションを開始 89demonstrateStreamSocketPair();
PHPのstream_socket_pair関数は、互いに接続された2つの双方向ソケットを作成する機能を提供します。この関数は主に、同じシステム内の異なるプログラム間での安全かつ信頼性の高いデータ交換(プロセス間通信)に利用されます。
引数$domainは通信に使用するプロトコルファミリを指定し、例えばAF_UNIXはローカルシステム内の通信に適しています。$typeはソケットの種類を指定し、SOCK_STREAMは信頼性のある接続指向通信を提供します。$protocolは使用するプロトコルを指定しますが、通常は0を指定してシステムに適切なプロトコルを選択させます。関数が成功すると、互いに接続されたソケットを表す2つのリソースを要素とする配列が返され、失敗した場合はfalseを返します。
サンプルコードでは、AF_UNIXドメインとSOCK_STREAMタイプでソケットペアを作成し、それらを$socketAと$socketBという変数に格納しています。これらのソケットは互いに接続されており、どちらからでもデータの読み書きが可能です。具体的には、fwrite関数でソケットAからソケットBへメッセージを送信し、fread関数でソケットBがそのメッセージを受信しています。同様に、ソケットBからソケットAへの返信も行われ、双方向の通信が確立される様子が示されています。通信終了後には、必ずfclose関数でソケットリソースを解放する必要があります。
stream_socket_pair関数は、主に同じコンピュータ上の異なるプログラム間での通信に使われます。この関数やデータの送受信を行うfwrite、freadなどは、実行に失敗することがありますので、必ず戻り値がfalseでないかを確認し、エラーが起きた場合の処理を記述してください。特に重要なのは、ソケットを使い終わったらfclose()関数で必ず閉じることです。これを忘れると、システムの資源が消費され続け、予期しない問題につながる可能性があります。また、freadはデータが届くまでプログラムの実行を停止させることがある点にも注意が必要です。
PHPでstream_socket_acceptを使ったサーバー処理
1<?php 2 3/** 4 * PHP Stream Socket Server Example with stream_socket_accept 5 * 6 * This script demonstrates how to create a simple server that listens for 7 * incoming client connections using `stream_socket_server` and accepts them 8 * using `stream_socket_accept`. 9 * 10 * Note for beginners: 11 * `stream_socket_pair` (from the reference information) creates a pair of already connected, unnamed sockets, 12 * typically used for inter-process communication within the same machine (e.g., between parent and child processes). 13 * 14 * `stream_socket_accept` (from the keyword) is used with a *listening* server socket 15 * (like the one created by `stream_socket_server`) to accept a new connection 16 * from a remote client. These two functions serve different purposes in socket programming. 17 * This example focuses on `stream_socket_accept` for server-client communication. 18 */ 19 20/** 21 * Starts a simple TCP socket server to accept and handle one client connection. 22 * 23 * @return void 24 */ 25function runSimpleSocketServer(): void 26{ 27 // Define the address and port for the server to listen on. 28 // 'tcp://127.0.0.1:8000' specifies a TCP socket on the localhost, port 8000. 29 $serverAddress = 'tcp://127.0.0.1:8000'; 30 31 // 1. Create a server socket. This function binds to an address and starts listening. 32 // It returns a resource representing the server socket or false on failure. 33 $server = stream_socket_server($serverAddress, $errno, $errstr); 34 35 if (false === $server) { 36 echo "Error: Could not create server socket: [$errno] $errstr\n"; 37 return; 38 } 39 40 echo "Server listening on {$serverAddress}...\n"; 41 echo "Waiting for a client connection...\n"; 42 43 // 2. Accept a client connection. 44 // This function blocks execution until a client attempts to connect to the server. 45 // It returns a resource representing the client's connection or false on failure. 46 // The second argument (-1) means it will wait indefinitely for a connection. 47 $client = stream_socket_accept($server, -1); 48 49 if (false === $client) { 50 echo "Error: Could not accept client connection.\n"; 51 // Close the server socket if client connection failed 52 fclose($server); 53 return; 54 } 55 56 echo "Client connected successfully!\n"; 57 58 // 3. Read data from the client. 59 // fread reads up to 1024 bytes from the client connection. 60 $request = fread($client, 1024); 61 echo "Received from client: " . trim((string) $request) . "\n"; 62 63 // 4. Send a response back to the client. 64 $response = "Hello from server! I received your message: \"" . trim((string) $request) . "\"\n"; 65 fwrite($client, $response); 66 echo "Sent to client: " . trim($response) . "\n"; 67 68 // 5. Close the client connection. 69 fclose($client); 70 echo "Client connection closed.\n"; 71 72 // 6. Close the server socket. 73 fclose($server); 74 echo "Server shut down.\n"; 75} 76 77// Execute the server function. 78runSimpleSocketServer(); 79 80/* 81 * How to test this server: 82 * 83 * 1. Save this code as `server.php`. 84 * 2. Run it from your terminal: `php server.php` 85 * The server will start and wait for a client. 86 * 87 * 3. Open another terminal and connect to it using `netcat` or a simple PHP client script. 88 * 89 * Example using netcat (if installed): 90 * `nc 127.0.0.1 8000` 91 * Type a message (e.g., "Hi server!") and press Enter. The server should respond. 92 * 93 * Example PHP client script (save as `client.php`): 94 * <?php 95 * $client = stream_socket_client("tcp://127.0.0.1:8000", $errno, $errstr, 30); 96 * if (false === $client) { 97 * echo "Error: Could not connect to server: [$errno] $errstr\n"; 98 * } else { 99 * $message = "Hello from PHP client!"; 100 * fwrite($client, $message); 101 * echo "Sent to server: {$message}\n"; 102 * echo "Received from server: " . fread($client, 1024); 103 * fclose($client); 104 * } 105 * ?> 106 * Run this client: `php client.php` 107 */
このPHPサンプルコードは、stream_socket_serverとstream_socket_accept関数を使用して、シンプルなTCPサーバーを構築し、クライアントとの通信を行う方法を示しています。
まず、リファレンス情報に記載されているstream_socket_pair関数は、$domain、$type、$protocolで指定された設定に基づき、既に接続状態にあるソケットのペアを作成します。この関数は主に、同じマシン上で動作するプロセス間での通信(プロセス間通信、IPC)に使用され、成功した場合は2つのソケットリソースを含む配列を、失敗した場合はfalseを返します。
一方、サンプルコードで利用されているstream_socket_accept関数は、stream_socket_serverなどで作成されたリスニング状態のサーバーソケットに対し、外部のクライアントからの接続要求を受け入れるために使われます。第一引数にはリスニング中のサーバーソケットリソースを、第二引数には接続を待つ最大時間(タイムアウト)を指定します。クライアントが正常に接続されると、そのクライアントとの通信に使用する新しいソケットリソースが返され、接続に失敗した場合はfalseが返されます。
このサンプルコードでは、まずstream_socket_serverで特定のIPアドレスとポートにサーバーを起動し、クライアントからの接続を待ち受けます。その後、stream_socket_acceptがクライアントからの接続を確立すると、クライアントから送信されたメッセージを読み込み、サーバーからの応答を返信します。通信が完了すると、クライアントソケットとサーバーソケットの両方を適切に閉じ、サーバーを終了します。このように、stream_socket_pairが主に内部的なプロセス間通信に用いられるのに対し、stream_socket_acceptは外部クライアントとの接続を処理する点で、それぞれ異なる役割を持っています。
リファレンスにあるstream_socket_pairはプロセス間通信用のソケットペアを生成する一方、サンプルコードで使われているstream_socket_acceptはサーバーがクライアントからの接続を受け入れる関数であり、用途が異なる点にご注意ください。stream_socket_acceptはクライアント接続があるまで処理が停止(ブロック)します。サーバーやクライアントソケットの作成、接続受け入れ、データの読み書きといった各ステップでエラー発生時にfalseが返されるため、必ず適切にエラーハンドリングを行うようにしてください。通信終了後は、fcloseを使ってサーバーソケットとクライアントソケットを確実に閉じ、リソースを解放することが重要です。このコードは単一のクライアント接続を処理するシンプルな例であり、複数のクライアントを同時に扱う場合は非同期処理やマルチプロセスなどのより高度な設計が必要となります。