ホームページ > バックエンド開発 > PHPチュートリアル > PHP はシステム プログラミング用にローカル ソケット (Unix ドメイン ソケット) を実装します。

PHP はシステム プログラミング用にローカル ソケット (Unix ドメイン ソケット) を実装します。

不言
リリース: 2023-03-23 16:54:01
オリジナル
3049 人が閲覧しました

この記事で共有する内容は、システム プログラミングの 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 = &#39;/dev/shm/unix.sock&#39;;
// 如果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&#39;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&#39;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 = &#39;/dev/shm/unix.sock&#39;;
// 如果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&#39;m another client
客户端关闭
客户端关闭
read data: I&#39;m the third client
客户端关闭
ログイン後にコピー


That‘s all!
相关推荐:

PHP实现系统编程之 多进程编程介绍及孤儿进程、僵尸进程

PHP实现系统编程之网络Socket及IO多路复用


以上がPHP はシステム プログラミング用にローカル ソケット (Unix ドメイン ソケット) を実装します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート