中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP+Socket中IO多路復用及實現web服務器的方法是什么

發布時間:2023-02-02 14:34:10 來源:億速云 閱讀:99 作者:iii 欄目:編程語言

本篇內容介紹了“PHP+Socket中IO多路復用及實現web服務器的方法是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

php原生socket之IO多路復用以及實現web服務器

多路復用

前文 通過原生 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 '請求ip: ' . $ip . '端口: ' . $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 == '') return;

            $output = '<h2>this is php worker</h2>';
            $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+Socket中IO多路復用及實現web服務器的方法是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

铁力市| 南汇区| 阆中市| 江安县| 汉源县| 玉龙| 万州区| 肇庆市| 胶州市| 保德县| 米脂县| 漳州市| 丁青县| 安平县| 咸丰县| 泽州县| 沾化县| 三亚市| 灵石县| 日照市| 南雄市| 普安县| 磐石市| 平阴县| 阳谷县| 青田县| 光泽县| 汉沽区| 景东| 赫章县| 夹江县| 临沂市| 额尔古纳市| 锡林郭勒盟| 临夏市| 新乡县| 灵台县| 广州市| 颍上县| 马龙县| 泗洪县|