首頁 後端開發 php教程 PHP實作系統程式設計之本地套接字(Unix Domain Socket)

PHP實作系統程式設計之本地套接字(Unix Domain Socket)

Apr 13, 2018 am 10:44 AM
php 套接字 本地

本篇文章給大家分享的內容是關於PHP實作系統程式設計之本地套接字(Unix Domain Socket),有著一定的參考價值,有需要的朋友可以參考一下

Socket API一開始是為了解決網路通訊而設計的,而後來在此之上又衍生出一種叫做本地套接字(Unix Domain Socket)的技術,本地套接字顧名思義,只支援本地的兩個進程之間進行通信,雖然網路套接字(Internet Domain Socket)也可以透過本地回環位址(127.0.0.1)來實現本地進程間通信,但由於本地套接字不需要經過網路協定棧,封包拆包、計算校驗和等操作,所以效率上比起網路套接字有一定的優點。由於本地套接字效能高、穩定、支援非血緣關係的進程間通訊,所以本地套接字也是當下使用最廣泛的IPC(進程間通訊)的機制之一。

Nginx 與PHP-FPM 之間使用網路套接字(127.0.0.1:9000)和使用本地套接字兩種通訊方式的效能對比

一般我們都是讓PHP-FPM 監聽127.0.0.1:9000 ,顯然這時Nginx 與PHP-FPM 是透過網路套接字來實現通訊的,其實,如果Nginx和PHP-FPM運作在同一台伺服器上,我們也可以讓PHP-FPM監聽本地套接字,接下來就針對這兩種方式的效能做一簡單的比較。

這裡我的Nginx開啟兩個worker程序

#
[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為socket程式設計提供了兩套API,一套是socket_* 系列方法,這在我們前面的系列文章裡演示過了,另一套是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手冊,這裡直接示範程式碼:#######################server端程式碼:##################
<?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);
登入後複製
############################################################### ####client端程式碼:#########################
<?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 Domain Socket)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 帶來了多項新功能、安全性改進和效能改進,同時棄用和刪除了大量功能。 本指南介紹如何在 Ubuntu、Debian 或其衍生版本上安裝 PHP 8.4 或升級到 PHP 8.4

CakePHP 日期和時間 CakePHP 日期和時間 Sep 10, 2024 pm 05:27 PM

為了在 cakephp4 中處理日期和時間,我們將使用可用的 FrozenTime 類別。

討論 CakePHP 討論 CakePHP Sep 10, 2024 pm 05:28 PM

CakePHP 是 PHP 的開源框架。它旨在使應用程式的開發、部署和維護變得更加容易。 CakePHP 基於類似 MVC 的架構,功能強大且易於掌握。模型、視圖和控制器 gu

CakePHP 檔案上傳 CakePHP 檔案上傳 Sep 10, 2024 pm 05:27 PM

為了進行文件上傳,我們將使用表單助理。這是文件上傳的範例。

CakePHP 建立驗證器 CakePHP 建立驗證器 Sep 10, 2024 pm 05:26 PM

可以透過在控制器中新增以下兩行來建立驗證器。

如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 如何設定 Visual Studio Code (VS Code) 進行 PHP 開發 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也稱為 VS Code,是一個免費的原始碼編輯器 - 或整合開發環境 (IDE) - 可用於所有主要作業系統。 VS Code 擁有大量針對多種程式語言的擴展,可以輕鬆編寫

CakePHP 快速指南 CakePHP 快速指南 Sep 10, 2024 pm 05:27 PM

CakePHP 是一個開源MVC 框架。它使應用程式的開發、部署和維護變得更加容易。 CakePHP 有許多函式庫可以減少大多數常見任務的過載。

您如何在PHP中解析和處理HTML/XML? 您如何在PHP中解析和處理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示瞭如何使用PHP有效地處理XML文檔。 XML(可擴展的標記語言)是一種用於人類可讀性和機器解析的多功能文本標記語言。它通常用於數據存儲

See all articles