玩轉 PHP 網路程式設計之原理篇

勺顛顛發表於2020-04-25

先扯蛋

本系列文章會對著手冊擼程式碼,而不是百度,CSDN,指令碼之家,google等上覆制別人的內容炒冷飯,而是隨心所欲拿著手冊直接擼。

PHP socket 手冊

手冊地址

使用需求

系統平臺
玩轉PHP網路程式設計全套

php -m 或 php --ri sockets

玩轉PHP網路程式設計全套

顯示如上,表示php已經支援socket擴充套件

幾行程式碼先執行

$ip = "0.0.0.0"; $port = $argv[1]; $sockefd = socket_create(AF_INET,SOCK_STREAM,0); echo $sockefd.PHP_EOL; $pid = posix_getpid(); echo "pid=".$pid.PHP_EOL; echo `ls -al /proc/{$pid}/fd`;//為了方便看該程式生成的資料 socket_bind($sockefd,$ip,$port); socket_listen($sockefd,5);  while (1){} 

然後我php socket1.php 12345
結果顯示如下
玩轉PHP網路程式設計全套
我先來解釋先
Resource id #4那是PHP返回的,在PHP裡稱為資源
0它是一個字元輸入裝置也是檔案描述符【linux皆檔案】
1它是一個字元輸出裝置也是檔案描述符
2同樣的也是
3比較特殊它是一個epoll型別的檔案,連結著一個匿名節點
4是一個socket型別的檔案,它的結點是9460457
5是一個管道檔案
實際上我去對應的目錄看是沒有這檔案的,可以先不理它
在linux上它是這樣的
玩轉PHP網路程式設計全套
接下來我們繼續看socket:[9460457]->4
先看它的網路狀態,我們cat net/tcp即可
玩轉PHP網路程式設計全套
先對幾個重要的選項解釋一下
local_address表示本地ip和埠號用16進製表示
rem_address 遠端伺服器ip和埠
st 表示套接字狀態
1 TCP_ESTABLISHED
2 TCP_SYN_SENT
3 TCP_SYN_RECV
4 TCP_FIN_WAIT1
5 TCP_FIN_WAIT2
6 TCP_TIME_WAIT
7 TCP_CLOSE
8 TCP_CLOSE_WAIT
9 TCP_LAST_ACK
10 TCP_LISTEN 16進位制就是A
11 TCP_CLOSING
tx_queue 傳送佇列中的資料長度
rx_queue 接收的資料長度
tr 定時器型別
0未啟動定時
1開啟socket 定時重傳機制
4開啟持續定時
2開啟連線定時器 FIN_WAIT2定時
3 TIME_WAIT定時

tm->when 超時時間
retrnsmt 超時重傳次數
uid 使用者的id
inode socket套接字對應的結點inode
大家都瞭解TCP資料流擁有自己的接收緩衝區和傳送緩衝區,同時呢具有超時重傳機制和資料應答確診機制

這個socket它的狀態用netstat -antp檢視就是這樣的
玩轉PHP網路程式設計全套

所以我們socket_create後它建立了一個TCP並且處於監聽狀態中即LISTEN。

我們在程式碼的最後一句加上了while就是讓它一直迴圈在那執行R(running),我們在該程式生成的目錄下可以檢視
玩轉PHP網路程式設計全套

發起一個網路連線一下看看效果

在發起連線之前我們先要執行tcpdump -i lo port 12345
然後使用telnet工具去連線,得到的結果如下
玩轉 PHP 網路程式設計全套
22:33:44.827309 IP localhost.37510 > localhost.italk: Flags [S], seq 1537400892
01:50:55.605018 IP localhost.italk > localhost.37510: Flags [S.], seq 1228325870, ack 1537400893
22:33:44.827328 IP localhost.37510 > localhost.italk: Flags [.], ack 1

前面的是時間,localhost.37510是客戶端的ip和系統分配的隨機埠
而localhost.italk是本機
Flags

  • SYN 表示發起一個連線
  • ACK 一個應答
  • RST 重新發起連線
  • PSH 在傳輸資料時會有這個標誌位
  • URG 緊急標誌位
  • FIN 一個關閉報文

seq 表示源IP向目標IP傳輸的序列號
對端應答的時候必須在其基礎上加1操作
ack 表示確認序列號,一般在seq上加1進行應答確認
以上的內容完成了大家比較熟悉的TCP連線三次握手

我想知道細節,想知道它到底在幹嘛

下面我來新增幾句程式碼,我們來更清楚的知道它們是怎麼玩在一起的,是怎麼進行通訊的

.... while (1){      $connfd = socket_accept($sockefd);     echo $connfd.PHP_EOL;     socket_write($connfd,"hello,php 是世界上是好的語言");  }

然後輸入如下命令

strace -f php socket1.php 12345

抽核心大概流程

  • exec
    玩轉 PHP 網路程式設計全套
  • read socket1.php
    玩轉 PHP 網路程式設計全套
  • create socket
    玩轉 PHP 網路程式設計全套
  • exec sh
    玩轉 PHP 網路程式設計全套
  • bind,listen,accept
    玩轉 PHP 網路程式設計全套
    就大概這麼幾句,建立socket返回檔案描述符4,然後bind繫結,監聽,最後呢在accept函式阻塞程式【Sleeping狀態】cpu已經做其它事情了,畢竟它在”睡覺中”
    玩轉 PHP 網路程式設計全套
    玩轉 PHP 網路程式設計全套

接下來我們同樣用telnet工具來連線並傳輸資料
玩轉 PHP 網路程式設計全套
玩轉 PHP 網路程式設計全套
玩轉 PHP 網路程式設計全套

玩轉 PHP 網路程式設計全套

接下來我們再加幾句程式碼讓其它成基本的響應給客戶端

while (1){     $connfd = socket_accept($sockefd);     echo $connfd.PHP_EOL;     socket_write($connfd,"hello,php 是世界上是好的語言");     echo socket_read($connfd,4098,PHP_BINARY_READ); } 

玩轉 PHP 網路程式設計全套

我們看到php語言低層呼叫了libc API【任何語言都是一樣】
都是先建立一個socketfd,再把埠和地址綁架到它身上,再listen進行監聽,直到accept阻塞,有客戶端連線時才會喚醒該程式來處理資料。所以務必動手實驗才能領略阻塞和喚醒的感覺。

玩轉 PHP 網路程式設計全套

本作品採用《CC 協議》,轉載必須註明作者和本文連結

只會php crud的渣渣

相關文章