PHP+Socket系列之IO多路復用及實作web伺服器

藏色散人
發布: 2023-04-11 10:20:01
轉載
4005 人瀏覽過

本篇文章為大家帶來了關於php socket的相關知識,其中主要介紹了IO多路復用,以及php socket如何實作web伺服器?有興趣的朋友下面一起來看一下,希望對大家有幫助。

php原生socket之IO多路復用以及實作網頁伺服器

多路復用

前文 透過原生socket 實現了簡單的服務端與客戶端通信,但當有多個客戶端連接時,服務端僅能處理第一個客戶端的請求,而無法對後續客戶端服務

PHP+Socket系列之IO多路復用及實作web伺服器

產生這種情況的原因是因為IO模型是阻塞的,同一時刻只能由一個客戶端進行訪問,解決此問題主要有兩種解決方案:

  • 多進程,即在服務端啟動多個進程監聽

  • IO多路復用機制,簡單來說實作了N 個用戶端使用一條網線同時存取

同時多路復用又分為兩個不同的模型,即selectepoll,常見的軟體中,Apache 使用了select 模型,nginx 則使用epoll 模型。在php 中內建了select 模型,對應的函數為socket_select,多路復用是實作http 伺服器的基礎

語法

#在前文我們介紹了php 原生socket 內建了socket_select 函式實作了select 模型,其語法如下:

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

參數

  • 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) {
        // 如果当前套接字等于 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;
        }
    }
}
登入後複製

在本範例中socket_select 函數會阻塞目前進程,當$tmp_sockets 陣列內的socket 資源有新的當客戶端連線或中斷或收到新訊息時,會將$tmp_sockets 陣列修改為目前活躍的socket 資源,隨後透過遍歷該陣列處理業務邏輯

PHP+Socket系列之IO多路復用及實作web伺服器

#使用socket實作簡易http伺服器

http 協定是在socket 的基礎上規定了指定的資料格式,所以我們只需在socket_write時按照格式發送數據,瀏覽器就可正常回應請求

<?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);
        }
    }
}
登入後複製

在服務端運行此範例,隨後在瀏覽器存取ip:8888 ,可以看到如下:

PHP+Socket系列之IO多路復用及實作web伺服器

同時服務端會輸出如下內容:

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
登入後複製

該內容即為用戶端請求原始數據,可解析此數據並根據請求做出回應,例如使用file_get_content 讀取指定檔案內容回傳至瀏覽器

推薦學習:《PHP視訊教學》               #       

#

以上是PHP+Socket系列之IO多路復用及實作web伺服器的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:learnku.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板