用php入門網絡編程


學習思路

以下是我對學習網絡編程的一個簡單的學習思路,之后我將會按照這個計划去逐步學習網絡編程相關的知識。

  1. step 1. 原生php實現TCP Server -> 原生php實現http協議 -> 掌握tcpdump的使用 -> 深刻理解tcp連接過程
  2. step 2. 原生php實現多進程webserver 2.1 引入I/O多路復用 2.2 引入php協程(yield) 2.3 對比 I/O多路復用版本 和 協程版本的性能差異
  3. step 3. 實現簡單的go web框架
  4. step 4. php c擴展實現簡單的webserver

什么我會選擇用php去學習網絡編程?因為對於我來說,php算是最熟悉的,其次php相對來說簡單些,同時php自身也有相應的函數支持。

我們今天先開始第一部分的學習。

正文

我們先簡單回顧下php作為后端語言的常見的交互方式過程:

client –(protocol:http)–> nginx –(protocol:fastcgi)–> php-fpm –(interface:sapi)–> php

在這里nginx充當的web server和反向代理server的角色,把http協議轉換成了fastcgi協議。看到這里有些小伙伴可能會說了:“如果php自己直接處理http請求,不就可以不用nginx&php-fpm了么?”遺憾的是原生php木有實現http協議(是吧,歡迎糾錯)。

然后可能又有小伙伴說:“原生php不是支持tcp協議么?nginx把http請求代理成tcp協議不就可以不用php-fpm了嗎。”,嗯,是的,沒錯。這位小伙伴的描述的交互過程如下

client –(protocol:http)–> nginx –(protocol:tcp)–> php

這樣看起來是沒啥問題,很不錯的想法,但是理論來說還是沒有實現http協議,接收到的內容應該還是一坨字符串。我們馬上來試一下:

STEP 1: 起一個NGINX服務
STEP 2: PHP簡單實現一個TCP SERVER,簡單的代碼如下

 

<?php

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

socket_bind($server, '127.0.0.1', '8889');
socket_listen($server);

while (true) {
    $client = socket_accept($server);
    if (! $client) {
        continue;
    }
    $request = socket_read($client, 1024);
    // 查看接收到的內容
    var_dump($request);
    socket_close($client);
}

 訪問結果

 

 

 所以我們就需要實現http協議,既然都實現了http協議,那就可以直接使用http作為web server了。

client –(protocol:http)–> php

接着我們看看如何用php創建一個簡單的TCP Server過程如下:

 

 

 

主要涉及的PHP函數如下

socket_create

socket_listen

socket_accept

socket_recv || socket_read

socket_write

socket_close

代碼如下

<?php

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

socket_bind($server, '127.0.0.1', '8889');

socket_listen($server);

while (true) {
    // accept
    $client = socket_accept($server);
    if (! $client) {
        continue;
    }
    $request = socket_read($client, 1024);
    socket_close($client);
    echo socket_strerror(socket_last_error($server)) . "\n";
}

沒毛病,TCP Server起來了。

原生PHP實現HTTP協議

上面簡單的TCP Server基本出來了,我們需要讓php直接成為一個Web Server,想一想Web Server是基於HTTP協議的,HTTP協議又是基於TCP協議實現的。也就是說我們在上面的TCP Server基礎上實現下HTTP協議即可。我們改進下流程圖加入HTTP部分(橙黃色),如下

 

 

實現HTTP協議的過程其實就是:

  1. 能讀懂發來請求的信息
  2. 能返回給瀏覽器等客戶端它們能懂的信息

協議無非就是雙方協定好的規范,一樣在HTTP/1.1中 請求&響應的格式基本如下

 請求:

<HTTP Method> <url> <HTTP Version>
<KEY>:<VALUE>\r\n
...
\r\n

響應:

<HTTP Version> <HTTP Status> <HTTP Status Description>
<KEY>:<VALUE>\r\n
...
\r\n

 所以簡單來說,我們的php代碼只要按照上面的規范解析和返回出對應的內容即可,簡單的代碼例子如下:

<?php
    $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    socket_bind($server, '127.0.0.1', '8889');
    socket_listen($server);
    $http = new HttpProtocol();
    
    while(true){
        $client = socket_accept($server);
        if (!$client){
            continue;
        }
        $request = socket_read($client, 1024);
        $http->response("hello word");
        socket_write($client, $http->resposeData);
        socket_close($client);
    }
    class HttpProtocol {
         private $header=[
            "http"=>"HTTP/1.1 200 OK",
            "content-type" => "Content-Type:text/html",
            "server" => "Server: php/0.0.1",
        ];
        public  $resposeData="";
        public function response($msg){
            $count = count($this->header);
            $finalData="";
            foreach($this->header as $key => $value){
                $finalData.=$value."\r\n";
            }
            $this->resposeData = $finalData."\r\n".$msg;
        }
    }

?>

運行代碼:

 

 

結果展示:

 參考網址[http://tigerb.cn/2018/11/24/php-network-programming/]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM