Heim  >  Artikel  >  Backend-Entwicklung  >  IO-Multiplexing der PHP+Socket-Serie und Implementierung eines Webservers

IO-Multiplexing der PHP+Socket-Serie und Implementierung eines Webservers

藏色散人
藏色散人nach vorne
2023-02-02 13:43:363927Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über PHP+Socket, in dem hauptsächlich das E/A-Multiplexing vorgestellt wird und wie PHP+Socket den Webserver implementiert? Freunde, die interessiert sind, können einen Blick darauf werfen. Ich hoffe, es wird für alle hilfreich sein.

PHP natives Socket-IO-Multiplexing und Implementierung eines Webservers

Multiplexing

Vorheriger Artikel Einfache Server-Client-Kommunikation wird über native Sockets erreicht, aber wenn mehrere Clients vorhanden sind, ist der Server verbunden kann nur die Anfrage des ersten Clients bearbeiten, aber keine nachfolgenden Clients bedienen. Der Grund für diese Situation ist, dass das E/A-Modell blockiert und nur ein Client gleichzeitig verwendet werden kann. Für den Zugriff gibt es zwei Hauptlösungen Lösen Sie dieses Problem:

IO-Multiplexing der PHP+Socket-Serie und Implementierung eines Webservers

Multiprozess, das heißt, mehrere Prozesse auf dem Server starten, um sie zu überwachen

  • IO-Multiplexing-Mechanismus, der einfach die Verwendung von N Clients implementiert. Gleichzeitiger Zugriff über ein Netzwerkkabel

  • Gleichzeitig Multiplexing ist in zwei verschiedene Modelle unterteilt, nämlich select und epoll. In allgemeiner Software verwendet Apache das select-Modell und nginx verwendet das epoll-Modell. In PHP ist ein select-Modell integriert, und die entsprechende Funktion ist socket_select. Multiplexing ist zunächst die Grundlage für die Implementierung eines http-Servers In diesem Artikel haben wir vorgestellt, dass der native PHP-Socket über eine integrierte socket_select-Funktion zur Implementierung des select-Modells verfügt. Seine Syntax lautet wie folgt:

    socket_select(
        array &$read,
        array &$write,
        array &$except,
        int $seconds [,
        int $microseconds = 0]): int|false

    Parameters

    • read

    Die vom Server überwachte Socket-Ressource. Wenn sie sich ändert (d. h. wenn eine neue Nachricht empfangen wird oder ein Client eine Verbindung herstellt oder trennt), wird der socket_select Funktion kann Es wird zurückgegeben (andernfalls wird es weiterhin blockiert) und gleichzeitig die Variable in die Socket-Ressourcenliste des aktuellen Ereignisses (empfangene Nachricht oder Clientverbindung oder -trennung) ändern und mit der Ausführung fortfahren nach unten. selectepoll,常见的软件中,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 资源,随后通过遍历该数组处理业务逻辑

    IO-Multiplexing der PHP+Socket-Serie und Implementierung eines Webservers

    使用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 ,可以看到如下:

    IO-Multiplexing der PHP+Socket-Serie und Implementierung eines Webservers

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

    rrreee

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

    writeÜberwachen Sie, ob der Client Daten schreibt. Die Übergabe von null bedeutet, dass es Ihnen egal ist, ob es Schreibänderungen gibt

    außer code>

    Das im Socket auszuschließende Element, das in null übergeben wird, ist „zuhören“. Alle 🎜🎜🎜🎜Sekunden🎜🎜Sekunden und Mikrosekunden bilden zusammen der Timeout-Parameter. Wenn null übergeben wird, wird es blockiert, und wenn es 0 ist, ist es nicht blockierend. Wenn es >0 ist, ist es die maximale Blockierungszeit🎜🎜🎜🎜Mikrosekunden🎜🎜🎜

    Optimierung🎜Wir haben Socket einfach in Vorheriger Artikel🎜 Der Server überwacht die Verbindung mit dem Client. Als nächstes optimieren wir den Code durch Multiplexen basierend auf dem Server-Überwachungscode: 🎜rrreee🎜In diesem Beispiel der socket_select-Funktion blockiert den aktuellen Prozess auf die aktuell aktive Socket-Ressource geändert werden und dann die Geschäftslogik durch Durchlaufen des Arrays verarbeiten🎜🎜Screenshot des Optimierungsergebnisses🎜 🎜🎜Verwenden Sie Socket, um einen einfachen http-Server zu implementieren🎜🎜🎜Das HTTP-Protokoll gibt das angegebene Datenformat basierend auf dem Socket an, sodass wir nur Daten gemäß dem Format senden müssen, wenn socket_write, und der Browser funktioniert normal. Reagieren Sie auf die Anfrage🎜rrreee🎜Führen Sie dieses Beispiel auf dem Server aus und greifen Sie dann im Browser auf ip:8888 zu. Sie können Folgendes sehen:🎜 🎜IO-Multiplexing der PHP+Socket-Serie und Implementierung eines Webservers🎜🎜At die Gleichzeitig gibt der Server den folgenden Inhalt aus: 🎜rrreee 🎜Dieser Inhalt sind die Rohdaten der Client-Anfrage. Sie können diese Daten analysieren und entsprechend der Anfrage antworten, indem Sie beispielsweise file_get_content verwenden, um die angegebenen Daten zu lesen Dateiinhalt ablegen und an den Browser zurückgeben 🎜🎜🎜Empfohlenes Lernen: „🎜PHP-Video-Tutorial🎜“ 🎜                                    🎜🎜

    Das obige ist der detaillierte Inhalt vonIO-Multiplexing der PHP+Socket-Serie und Implementierung eines Webservers. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:learnku.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen