この記事で共有する内容は、システム プログラミングの PHP 実装におけるローカル ソケット (Unix ドメイン ソケット) に関するもので、必要な場合は参照してください。
ソケット API は元々、問題を解決するために設計されました。ネットワークの問題 通信のために設計され、その後、Unix ドメイン ソケットと呼ばれる技術が派生しました。その名前が示すように、ローカル ソケットは 2 つのローカル プロセス間の通信のみをサポートしますが、ネットワーク ソケット (インターネット ドメイン ソケット) はローカル相互接続も実現できます。ローカル ループバック アドレス (127.0.0.1) を介して通信を処理しますが、ローカル ソケットはネットワーク プロトコル スタック、パケットのアンパック、チェックサムの計算、その他の操作を通過する必要がないため、ネットワーク ソケットに比べて特定の利点があります。効率の観点から。ローカル ソケットは高性能、安定性が高く、血液に関係のないプロセス間通信をサポートしているため、最も広く使用されている IPC (プロセス間通信) メカニズムの 1 つでもあります。
ネットワークソケット (127.0.0.1:9000) を使用した場合とローカルソケットを使用した場合の Nginx と PHP-FPM のパフォーマンスの比較
一般的に、Nginx と PHP は明らかに PHP-FPM モニター 127.0.0.1:9000 を使用します。 -FPM は現時点ではネットワーク ソケットを介して通信します。実際、Nginx と PHP-FPM が同じサーバー上で実行されている場合、PHP-FPM にローカル ソケットを監視させることもできます。これら 2 つの方法のパフォーマンスを簡単に比較してみましょう。 。
ここで、私のNginxは2つのワーカープロセスを開始します
[root@localhost ~]# ps -ef | grep nginx root 1838 1 0 22:48 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 1839 1838 0 22:48 ? 00:00:00 nginx: worker process nginx 1840 1838 0 22:48 ? 00:00:00 nginx: worker process root 1851 1797 0 22:49 pts/0 00:00:00 grep nginx
ネットワークソケットを使用したNginxとPHP-FPMの構成は次のとおりです:
ストレステストtest.phpスクリプト
<?php phpinfo();
ストレステストの結果:
Nginx と PHP を見てみましょう - FPM はローカル ソケット通信を使用し、Nginx と PHP-FPM の構成が少し変更されています:
ストレステストの結果:
結果から、ローカルソケットはネットワークソケットと比較して平均的なQPSを持っていることがわかります。 100 ポイント以上高く、これは基本的に私たちの予想と一致しています。
PHPのローカルソケットプログラミング
実際、PHPのローカルソケットプログラミングは、渡されるパラメーターが異なることを除いて、基本的にネットワークソケットと同じです。
PHP は、ソケット プログラミング用に 2 つの API セットを提供します。1 つは、以前の一連の記事で説明した、socket_* シリーズのメソッドで、もう 1 つは、stream_socket_* シリーズのメソッドです。便宜上、ここでは後者をデモンストレーションに使用します。
stream_socket_* メソッドリスト:
•stream_socket_accept — 接受由 stream_socket_server 创建的套接字连接 •stream_socket_client — Open Internet or Unix domain socket connection •stream_socket_enable_crypto — Turns encryption on/off on an already connected socket •stream_socket_get_name — 获取本地或者远程的套接字名称 •stream_socket_pair — 创建一对完全一样的网络套接字连接流 •stream_socket_recvfrom — Receives data from a socket, connected or not •stream_socket_sendto — Sends a message to a socket, whether it is connected or not •stream_socket_server — Create an Internet or Unix domain server socket •stream_socket_shutdown — Shutdown a full-duplex connection
具体的なメソッドについてはPHPマニュアルを参照してください。直接のデモコードは次のとおりです:
サーバーコード:
<?php //stream_server.php $sockfile = '/dev/shm/unix.sock'; // 如果sock文件已存在,先尝试删除 if (file_exists($sockfile)) { unlink($sockfile); } $server = stream_socket_server("unix://$sockfile", $errno, $errstr); if (!$server) { die("创建unix domain socket fail: $errno - $errstr"); } while(1) { $conn = stream_socket_accept($server, 5); if ($conn) { while(1) { $msg = fread($conn, 1024); if (strlen($msg) == 0) //客户端关闭 { fclose($conn); break; } echo "read data: $msg"; fwrite($conn, "read ok!"); } } } fclose($server);
クライアントコード:
<?php //stream_client.php $client = stream_socket_client("unix:///dev/shm/unix.sock", $errno, $errstr); if (!$client) { die("connect to server fail: $errno - $errstr"); } while(1) { $msg = fread(STDIN, 1024); if ($msg == "quit\n") { break; } fwrite($client, $msg); $rt = fread($client, 1024); echo $rt . "\n"; } fclose($client);
运行
server端:
[root@localhost html]# php stream_server.php read data: hello unix domain socket read data: are you ok? read data: I'm fine! PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13
client端:
[root@localhost html]# php stream_client.php hello unix domain socket read ok! are you ok? read ok! I'm fine! read ok! ^C
以上是一个最简单的本地套接字的代码演示,细心的读者可能注意到了server端报的warning,服务器如果长时间没有客户端过来连接,超过了stream_socket_accept 方法设置的timeout,服务器端便会报这个警告,事实上,真正的服务端代码是不会是像这样写的,因为这种方式同一时间只能处理一个客户端连接,如果要实现并发,一种方式就是使用IO多路复用,如同 socket_* 系列方法中有socket_select 方法 (参考系列文章第一篇http://blog.csdn.net/zhang197093/article/details/77366407),stream_socket_* 系列方法提供了 stream_select 方法来实现多路复用,使用方法也很相似。
int stream_select ( array &$read , array &$write , array &$except , int $tv_sec [, int $tv_usec = 0 ] )
The stream_select() function accepts arrays of streams and waits for them to change status. Its operation is equivalent to that of the socket_select() function except in that it acts on streams.
详细的方法介绍请参考PHP手册 : http://php.net/manual/zh/function.stream-select.php
优化后的代码如下:
<?php //stream_server.php $sockfile = '/dev/shm/unix.sock'; // 如果sock文件已存在,先尝试删除 if (file_exists($sockfile)) { unlink($sockfile); } $server = stream_socket_server("unix://$sockfile", $errno, $errstr); if (!$server) { die("创建unix domain socket fail: $errno - $errstr"); } $listen_reads = array($server); $listen_writes = array(); $listen_excepts = NULL; while(1) { $can_reads = $listen_reads; $can_writes = $listen_writes; $num_streams = stream_select($can_reads, $can_writes, $listen_excepts, 0); if ($num_streams) { foreach ($can_reads as &$sock) { if ($server == $sock) { $conn = stream_socket_accept($server, 5); //此时一定存在客户端连接,不会有超时的情况 if ($conn) { // 把客户端连接加入监听 $listen_reads[] = $conn; $listen_writes[] = $conn; } } else { $msg = fread($sock, 1024); //此时一定是可读的 if (strlen($msg) == 0) //读取到0个字符,说明客户端关闭 { fclose($sock); // 从sock监听中移除 $key = array_search($sock, $listen_reads); unset($listen_reads[$key]); $key = array_search($sock, $listen_writes); unset($listen_writes[$key]); echo "客户端关闭\n"; } else { echo "read data: $msg"; // 是否可写 if (in_array($sock, $can_writes)) { fwrite($conn, "read ok!"); } } } } } } fclose($server);
此时这个server就不会有前面那个Warning了,并且支持并发
[root@localhost html]# php stream_server.php read data: hello world read data: hello unix domain socket read data: harry up read data: read data: read data: I'm another client 客户端关闭 客户端关闭 read data: I'm the third client 客户端关闭
That‘s all!
相关推荐:
以上がPHP はシステム プログラミング用にローカル ソケット (Unix ドメイン ソケット) を実装します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。