短文1:使用 php-socket 簡述 http 伺服器原理

php_yt發表於2020-12-27

此節使用 PHP 原生 Socket 演示完成 http 請求的原理

套接字怎麼理解

一個典型的網路連線由 2 個套接字構成,一個執行在客戶端,另一個執行在伺服器端。

“套接字”取名叫做 socket,翻譯:“插座”。在網路程式設計中叫做用於網路資料傳輸的“軟體裝置”。

那麼通俗理解一點,“套接字” 就是一個檔案資源 file

socket 示意圖

以一家拉麵館做比喻

流程概要:假設場景是食城,一家拉麵店。透過 create 建立一個服務端套接字,初始化套接字有三個引數,是ipv4還是ipv6、面向連線還是面向訊息、tcp 還是 udp ,也就是描述這個套接字是幹嘛用,描述我是一家拉麵館。接下來透過 bind 埠號,也就是聯絡地址,食城第123號能找到我。透過 listen 開始監聽,準備好了開始營業(這時店裡沒人接待,顧客排隊等候)。呼叫 accept 函式等待客戶端連線(此處阻塞,直到有客戶端連線產生一個客戶端檔案描述符 fd ),也就是等待客人,直到來了一個顧客,此時店員拿起一張紙片問顧客問吃點啥,隨後將紙片轉給後廚。後廚 read 紙片上的菜品,然後準備食物 響應,然後 write 給顧客。顧客走了,卡片也就沒用了扔掉了(fd回收),socket_close($client) 結束該顧客的服務。晚上10點,拉麵店關門,socket_close($server)

PHP 程式碼

建立一個套接字,$server 表示的是服務端的套接字。描述我是拉麵館。

$server = socket_create(
AF_INET, 
SOCK_STREAM, 
SOL_TCP);

繫結埠號,0.0.0.0 服務所有人,當然也可以是專供

socket_bind($socket, '0.0.0.0', 80);

開始監聽,5 排隊中等待接待的顧客人數,地方小門口只能站5個人(資源層面)。

socket_listen($socket, 5);

與一個客戶端建立連線,接待了張三

$client = socket_accept($server);

讀取客戶端訊號,張三:⌈來大碗拉麵加個蛋⌉,服務員拿紙記錄下來

$buf = socket_read($client, 1024);

處理訊號,後廚閱讀紙片,製片內容如下

$content = 'hello! i am server!';
$http_resonse = "HTTP/1.1 200 OK\r\n"; $http_resonse .= "Content-Type: text/html;charset=UTF-8\r\n"; $http_resonse .= "Connection: keep-alive\r\n"; $http_resonse .= "Server: php socket server\r\n"; $http_resonse .= "Content-length: ".strlen($content)."\r\n\r\n"; $http_resonse .= $content;

向客戶端寫入訊號,上菜品

socket_write($client,$http_resonse);

關閉客戶端,資源回收。系統建立的資源描述符是有限的(因為每個資源描述符都要開啟輸入輸出緩衝區,如果不及時回收資源,記憶體就會被佔滿)

socket_close($client);

關閉服務端,店面關門

socket_close($server);

處理訊號

上邊讀取到客戶端的訊號buf,如果我請求的地址是這樣:
請求  URL
列印buf:
socket 列印buf
buf是一長串字串,用正則來匹配該字串:

$preg = '#GET (.*) HTTP/1.1#iU';
preg_match($preg, $buf, $arr);
$request = $arr[1];

匹配的 (.*)是:
uri
這樣我們就拿到了請求的內容。

響應

如果是載入靜態頁面:

靜態頁面
獲取的檔名是
靜態頁面檔名
那麼 $response是:

$filePath = __DIR__ . '/html' . $path;
$content = file_get_contents($filePath);

如果是 php 檔案:

請求的是php檔案
獲取的檔名是:
獲取的檔名是
那麼 $response 是:

$filePath = __DIR__ . '/php' . $path;
ob_start();
include $filePath; //這裡執行了一段php邏輯程式碼
$content = ob_get_contents();
ob_clean();
本作品採用《CC 協議》,轉載必須註明作者和本文連結
welcome come back

相關文章