>  기사  >  백엔드 개발  >  PHP+Socket 시리즈의 IO 다중화 및 웹서버 구현

PHP+Socket 시리즈의 IO 다중화 및 웹서버 구현

藏色散人
藏色散人앞으로
2023-02-02 13:43:363927검색

이 기사는 주로 IO 멀티플렉싱을 소개하는 php+socket에 대한 관련 지식과 php+socket이 웹 서버를 구현하는 방법을 제공합니다. 관심 있는 친구들은 아래를 살펴보시면 모두에게 도움이 되길 바랍니다.

PHP 네이티브 소켓 IO 다중화 및 웹 서버 구현

multiplexing

이전글 간단한 서버-클라이언트 통신은 네이티브 소켓을 통해 이루어지지만, 클라이언트가 여러 개인 경우 클라이언트가 연결되면 서버는 첫 번째 클라이언트의 요청만 처리할 수 있지만 후속 클라이언트에 서비스를 제공할 수 없는 이유는 IO 모델이 차단되고 동시에 하나의 클라이언트만 사용할 수 있기 때문입니다. 액세스하려면 두 가지 주요 솔루션이 있습니다. 이 문제 해결:

PHP+Socket 시리즈의 IO 다중화 및 웹서버 구현

다중 프로세스, 즉 서버에서 여러 프로세스를 시작하여 모니터링

  • N 클라이언트 사용을 간단히 구현하는 IO 다중화 메커니즘 하나의 네트워크 케이블을 통한 동시 액세스

  • 동시 멀티플렉싱은 selectepoll이라는 두 가지 모델로 나뉩니다. 일반적인 소프트웨어에서 Apacheselect 모델을 사용합니다. , nginxepoll 모델을 사용합니다. PHP에는 select 모델이 내장되어 있으며 해당 함수는 socket_select입니다. 멀티플렉싱은 먼저 http 서버

    구문

    을 구현하는 기초입니다. 이 기사에서는 PHP 네이티브 소켓에 select 모델을 구현하는 내장 socket_select 함수가 있음을 소개했습니다. 해당 구문은 다음과 같습니다.
socket_select(
    array &$read,
    array &$write,
    array &$except,
    int $seconds [,
    int $microseconds = 0]): int|false

매개변수

    readselectepoll,常见的软件中,Apache 使用了 select 模型,nginx 则使用 epoll 模型。在 php 中内置了 select 模型,对应的函数为 socket_select,多路复用是实现 http 服务器的基础

    语法

    在前文中我们介绍了 php 原生 socket 内置了 socket_select 函数实现了 select 模型,其语法如下:

    <?php
    
    // 创建套接字
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    
    // 设置 ip 被释放后立即可使用
    socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, true);
    
    // 绑定ip与端口
    socket_bind($socket, 0, 8888);
    
    // 开始监听
    socket_listen($socket);
    
    $sockets[] = $socket;
    
    while (true) {
        $tmp_sockets = $sockets;
        socket_select($tmp_sockets, $write, $except, null);
    
        foreach ($tmp_sockets as $sock) {
            // 如果当前套接字等于 socket_create 创建的套接字,说明是有新的连接或有新的断开连接
            if ($sock == $socket) {
                $conn_sock = socket_accept($socket);
                $sockets[] = $conn_sock;
                socket_getpeername($conn_sock, $ip, $port);
                echo &#39;请求ip: &#39; . $ip . &#39;端口: &#39; . $port . PHP_EOL;
            } else { // 否则说明是之前连接的客户端发来消息
                $msg = socket_read($sock, 10240);
                socket_write($sock, strtoupper($msg));
                echo $msg;
            }
        }
    }

    参数

    • read

      服务端监听的套接字资源,当他有变化(即收到新的消息或有客户端连接、断开)时,socket_select 函数才会返回(否则继续阻塞),同时修改该变量为当前发生事件(收到消息或有客户端连接、断开)的套接字资源列表,并继续向下执行。

    • write

      监听是否有客户端写数据,传入 null 则代表不关心是否有写变化

    • except

      套接字内要排除的元素,传入 null 是 「监听」 全部

    • seconds

      秒和微秒一起构成超时参数。如果传入 null 则会阻塞,为 0 非阻塞,如果是 >0 则为最大阻塞时间

    • microseconds

    优化

    我们在 上篇文章 简单实现了 socket 服务端监听与客户端的连接,接下来我们在服务端监听代码的基础上通过多路复用优化代码:

    <?php
    
    // 创建套接字
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    
    // 设置 ip 被释放后立即可使用
    socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, true);
    
    // 绑定ip与端口
    socket_bind($socket, 0, 8888);
    
    // 开始监听
    socket_listen($socket);
    
    $sockets[] = $socket;
    
    while (true) {
        $tmp_sockets = $sockets;
        socket_select($tmp_sockets, $write, $except, null);
    
        foreach ($tmp_sockets as $sock) {
            if ($sock == $socket) {
                $conn_sock = socket_accept($socket);
                $sockets[] = $conn_sock;
            } else {
                $msg = socket_read($sock, 10240);
                var_dump($msg);
                if ($msg == &#39;&#39;) return;
    
                $output = &#39;<h1>this is php worker</h1>&#39;;
                $len = strlen($output);
    
                $response = "HTTP/1.1 200 OK\r\n";
                $response .= "content-type: text/html\r\n";
                $response .= "server: php socket\r\n";
                $response .= "Content-Length: {$len}\r\n\r\n";
    
                $response .= $output;
    
                socket_write($sock, $response);
            }
        }
    }

    在本示例中 socket_select 函数会阻塞当前进程,当 $tmp_sockets 数组内的 socket 资源有新的客户端连接或断开或收到新消息时,会将 $tmp_sockets 数组修改为当前活跃的 socket 资源,随后通过遍历该数组处理业务逻辑

    PHP+Socket 시리즈의 IO 다중화 및 웹서버 구현

    使用socket实现简易http服务器

    http 协议是在 socket 的基础上规定了指定的数据格式,所以我们只需在 socket_write 时按照格式发送数据,浏览器就可正常响应请求

    GET / HTTP/1.1
    Host: 124.222.**.**:8888
    Connection: keep-alive
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: jenkins-timestamper-offset=-28800000; _ga=GA1.1.1403944751.1652010033; _ga_2GM6102E19=GS1.1.1652802985.7.1.1652803014.0

    在服务端运行此示例,随后在浏览器访问 ip:8888 ,可以看到如下:

    PHP+Socket 시리즈의 IO 다중화 및 웹서버 구현

    同时服务端会输出如下内容:

    rrreee

    该内容即为用户端请求原始数据,可解析此数据并根据请求做出响应,比如使用 file_get_content

    서버에서 모니터링하는 소켓 리소스입니다. 변경되면(즉, 새 메시지가 수신되거나 클라이언트가 연결되거나 연결이 끊어지는 경우) 소켓_선택 함수는 반환할 것이며(그렇지 않으면 계속 차단됩니다) 동시에 현재 이벤트(수신된 메시지 또는 클라이언트 연결 또는 연결 끊김)의 소켓 리소스 목록에 대한 변수를 수정하고 계속 실행합니다. 하향의.

    write

    클라이언트가 데이터를 쓰는지 여부를 모니터링합니다. null을 전달하면 쓰기 변경 사항이 있는지 상관하지 않는다는 뜻입니다

    Except code>🎜🎜 소켓에서 제외될 요소, <code>null 전달은 "수신"입니다. 모두 🎜🎜🎜🎜🎜🎜초와 마이크로초를 함께 구성합니다. 시간 초과 매개변수. null이 전달되면 차단되고, 0이면 차단되지 않습니다.>0이면 최대 차단 시간이 됩니다🎜🎜🎜🎜마이크로초🎜🎜🎜

    최적화

    🎜우리는 이전 기사🎜 서버는 클라이언트와의 연결을 모니터링합니다. 다음으로 서버 모니터 코드를 기반으로 멀티플렉싱을 통해 코드를 최적화합니다. 🎜rrreee🎜이 예에서는 socket_select 함수는 $tmp_sockets 배열의 소켓 리소스에 새로운 클라이언트 연결 또는 연결 끊김이 있거나 새 메시지를 수신할 때 $tmp_sockets 배열을 차단합니다. 현재 활성 소켓 리소스로 수정한 다음 배열을 순회하여 비즈니스 로직을 처리합니다🎜🎜🎜 🎜🎜소켓을 사용하여 간단한 http 서버 구현🎜🎜🎜http 프로토콜은 소켓을 기반으로 지정된 데이터 형식을 지정하므로 socket_write, 그러면 브라우저가 정상적으로 작동합니다. 🎜rrreee🎜 요청에 대한 응답으로 이 예제를 서버에서 실행한 후 브라우저에서 ip:8888에 액세스하면 다음을 볼 수 있습니다. : 🎜🎜PHP+Socket 시리즈의 IO 다중화 및 웹서버 구현 🎜🎜 동시에 서버는 다음 콘텐츠를 출력합니다: 🎜rrreee 🎜이 콘텐츠는 클라이언트 요청 원시 데이터입니다. 이 데이터를 구문 분석하고 file_get_content를 사용하여 요청에 따라 응답할 수 있습니다. 지정된 파일 내용을 브라우저로 반환합니다🎜🎜🎜추천 학습: "🎜PHP 비디오 튜토리얼🎜" 🎜                             🎜🎜

    위 내용은 PHP+Socket 시리즈의 IO 다중화 및 웹서버 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제