PHPマルチスレッドサーバーの実装

この出版物は、質問に対する完全な解決策であると主張していません。 サーバーは、教育目的でのみ開発されています。 たとえば、ソケットエラーの処理など、多くの重要な問題は省略されています。 マルチスレッドサーバーを実装するには、もちろんスレッドを使用します。 PHPにはスレッドが存在しないというフレーズを頻繁に見る必要があります。 したがって、これは真実ではありません。 スレッドはありますが、個別のpthreads拡張機能で実装されています



まず、スレッドセーフティフラグを使用してコンパイルされたPHPアセンブリが必要です。 作業にはWindowsを使用しているため、完成したパッケージをここからダウンロードしました 。 OSの正しいビット深度、PHPの目的のバージョン、そしてもちろん、スレッドセーフバージョンを選択するだけです。 記事全体を通して、PHPを使用してアーカイブをC:\ phpディレクトリに解凍したと想定されます。 次に、pthreads拡張機能をインストールする必要があります。 ここに行き、ダウンロードしたPHPのバージョンとシステムの容量に対応するバージョンを選択します。 アーカイブから、php_pthreads.dllファイルをC:\ php \ extディレクトリにコピーし、pthreadVC2.dllファイルをC:\ phpおよびC:\ Windows \ System32ディレクトリにコピーします。 C:\ phpディレクトリで、php.ini-developmentファイルの名前をphp.iniに変更し、次の行を追加します。



extension=php_pthreads.dll
      
      





また、extension_dirディレクティブを見つけて解凍し、「C:\ php \ ext」に設定します(PHP7のバージョンでは、相対パスは機能しませんでした)。 コマンドラインを開き、次を確認します。



 C:\php\php.exe -v
      
      





出力の最初の行の最後に、マーク(ZTS)が表示されます。 サーバー実装に直接渡します。 ファイルを作成します(私の場合、C:\ server.phpにあります。まず、ローカルマシンのポート8080でリッスンするソケットを作成します。



 $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_bind($server, '127.0.0.1', 8080); socket_listen($server);
      
      





次に、ワーカーのプールを作成します。



 $pool = new Pool(10, Worker::class);
      
      





最初の引数はアクティブなスレッドの最大数を設定し、2番目はワーカーのクラス名です。 より具体的なタスクについては、Workerクラスから継承してクラスを説明できます。 元のクラスを使用します。 今後、スレッドクラスでは、$ this-> workerを使用してインストール済みワーカーを取得できると言います。



次に、別のスレッドで実行されるクラスを実装します。 クラスはThreadedから継承する必要があります。



 class Task extends Threaded { protected $socket; public function __construct($socket) { $this->socket = $socket; } public function run() { if (!empty($this->socket)) { $response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 12\r\n\r\nHello world!"; socket_write($this->socket, $response, strlen($response)); //        zend_mm_heap currupted,        //socket_close($this->socket); } } }
      
      





このクラスは、コンストラクターでクライアント接続ソケットを受け入れます。 また、ストリームで実行されるアクションは、run()メソッドで記述する必要があります。 私の場合、これはベースヘッダーとテキスト「Hello world!」を含むクライアントへの回答です。



次に、クライアントからの接続を周期的に受け入れ、成功した場合は別のストリームを作成し、そこにソケット記述子を渡します。



 $servers = [$server]; while (true) { $read = $servers; if (socket_select($read, $write, $except, 0) >= 0 && in_array($server, $read)) { $task = new Task(socket_accept($server)); $pool->submit($task); } }
      
      





無限ループを使用するため、スクリプトが完了してプールを停止したときに実行される関数を登録します。 関数は、サイクルの開始前に登録する必要があります。



 register_shutdown_function(function () use ($server, $pool) { if (!empty($server)) { socket_close($server); } $pool->shutdown(); });
      
      





実際にはすべて。 コマンドラインでサーバーを起動し、ブラウザーでlocalhost :8080を開きます。



 cd C:\ C:\php\php.exe server.php
      
      





以下は完全なサーバーコードです。



 <?php $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_bind($server, '127.0.0.1', 8080); socket_listen($server); $pool = new Pool(10, Worker::class); class Task extends Threaded { protected $socket; public function __construct($socket) { $this->socket = $socket; } public function run() { if (!empty($this->socket)) { $response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 12\r\n\r\nHello world!"; socket_write($this->socket, $response, strlen($response)); } } } register_shutdown_function(function () use ($server, $pool) { if (!empty($server)) { socket_close($server); } $pool->shutdown(); }); $servers = [$server]; while (true) { $read = $servers; if (socket_select($read, $write, $except, 0) >= 0 && in_array($server, $read)) { $task = new Task(socket_accept($server)); $pool->submit($task); } }
      
      





ご清聴ありがとうございました!



All Articles