> 백엔드 개발 > PHP 튜토리얼 > PHP는 시스템 프로그래밍을 위해 로컬 소켓(Unix Domain Socket)을 구현합니다.

PHP는 시스템 프로그래밍을 위해 로컬 소켓(Unix Domain Socket)을 구현합니다.

不言
풀어 주다: 2023-03-23 16:54:01
원래의
3023명이 탐색했습니다.

이 기사에서 공유한 내용은 시스템 프로그래밍의 PHP 구현에서 로컬 소켓(Unix Domain Socket)에 관한 것입니다. 이는 특정 참조 값을 가지고 있습니다. 필요한 친구가 이를 참조할 수 있습니다.

Socket API는 원래 이러한 문제를 해결하기 위해 설계되었습니다. 네트워크 문제 통신을 위해 설계되었으며 나중에 Unix Domain Socket이라는 기술이 파생되었습니다. 이름에서 알 수 있듯이 로컬 소켓은 두 로컬 프로세스 간의 통신만 지원하지만 네트워크 소켓 소켓(인터넷 도메인 소켓)도 로컬 상호 연결을 실현할 수 있습니다. 로컬 루프백 주소(127.0.0.1)를 통해 통신을 처리하지만 로컬 소켓은 네트워크 프로토콜 스택, 패킷언패킹, 체크섬 계산 및 기타 작업을 거칠 필요가 없으므로 네트워크 소켓에 비해 확실한 장점이 있습니다. 효율성의 조건. 로컬 소켓은 높은 성능, 안정성 및 비혈연 관련 프로세스 간 통신을 지원하므로 로컬 소켓은 가장 널리 사용되는 IPC(Inter-Process Communication) 메커니즘 중 하나이기도 합니다.

네트워크 소켓(127.0.0.1:9000)과 로컬 소켓을 사용한 Nginx와 PHP-FPM의 성능 비교

일반적으로 우리는 PHP-FPM 모니터 127.0.0.1:9000을 사용합니다. 당연히 Nginx와 PHP를 사용합니다. -FPM은 이때 네트워크 소켓을 통해 통신합니다. 실제로 Nginx와 PHP-FPM이 동일한 서버에서 실행되는 경우 PHP-FPM이 로컬 소켓을 모니터링하도록 할 수도 있습니다. 이 두 가지 방법의 성능을 간단하게 비교해 보겠습니다. .

여기서 내 Nginx는 두 개의 작업자 프로세스를 시작합니다

[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의 구성이 약간 수정되었습니다.

스트레스 테스트 결과 :


ㅋㅋㅋ 100포인트 이상 높았으며 이는 기본적으로 우리의 기대와 일치합니다.




PHP의 로컬 소켓 프로그래밍


실제로 PHP의 로컬 소켓 프로그래밍은 전달되는 매개변수가 다르다는 점을 제외하면 기본적으로 네트워크 소켓과 동일합니다.

PHP는 소켓 프로그래밍을 위한 두 가지 API 세트를 제공합니다. 하나는 이전 기사 시리즈에서 설명한 소켓_* 시리즈 메서드이고, 후자는 더 많습니다. 사용하기 편리합니다. 편의상 여기서는 후자를 사용하여 설명합니다.

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
//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 Domain Socket)을 구현합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿