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); } } 

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

Source: https://habr.com/ru/post/J312662/


All Articles