日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

php后端如何搭建socket服务,从php做一个简单的socket服务器流程

發布時間:2023/12/19 php 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php后端如何搭建socket服务,从php做一个简单的socket服务器流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

socket的中文名字稱為套接字,這類物品就是說對TCP/iP的“封裝”。實際中的互聯網事實上只能四層罷了,從上至下分別是網絡層、傳輸層、網絡層、統計數據鏈路層。最常見的.com協議書則是歸屬于網絡層的協議書,而socket,能夠死板的了解為是傳輸層的這種物品。要是還是沒辦法了解,那再粗魯地一點兒tcp://218.221.11.23:9999,看到沒?這就是一個tcp socket。

socket賦予了我們操控傳輸層和網絡層的能力,從而得到更強的性能和更高的效率,socket編程是解決高并發網絡服務器的最常用解決和成熟的解決方案。任何一名服務器程序員都應當掌握socket編程相關技能。

在php中,可以操控socket的函數一共有兩套,一套是socket_系列的函數,另一套是stream_系列的函數。socket_是php直接將C語言中的socket抄了過來得到的實現,而stream_系則是php使用流的概念將其進行了一層封裝。下面用socket_*系函數簡單為這一系列文章開個篇。

先來做個最簡單socket服務器:<?php

$host?=?'0.0.0.0';

$port?=?9999;

//?創建一個tcp?socket

$listen_socket?=?socket_create(?AF_INET,?SOCK_STREAM,?SOL_TCP?);

//?將socket?bind到IP:port上

socket_bind(?$listen_socket,?$host,?$port?);

//?開始監聽socket

socket_listen(?$listen_socket?);

//?進入while循環,不用擔心死循環死機,因為程序將會阻塞在下面的socket_accept()函數上

while(?true?){

//?此處將會阻塞住,一直到有客戶端來連接服務器。阻塞狀態的進程是不會占據CPU的

//?所以你不用擔心while循環會將機器拖垮,不會的

$connection_socket?=?socket_accept(?$listen_socket?);

//?向客戶端發送一個helloworld

$msg?=?"helloworld

";

socket_write(?$connection_socket,?$msg,?strlen(?$msg?)?);

socket_close(?$connection_socket?);

}

socket_close(?$listen_socket?);

將文件保存為server.php,然后執行php server.php運行起來。客戶端我們使用telnet就可以了,打開另外一個終端執行telnet 127.0.0.1 9999按下回車即可。運行結果如下:

簡單解析一下上述代碼來說明一下tcp socket服務器的流程:1.首先,根據協議族(或地址族)、套接字類型以及具體的的某個協議來創建一個socket。

2.第二,將上一步創建好的socket綁定(bind)到一個ip:port上。

3.第三,開啟監聽linten。

4.第四,使服務器代碼進入無限循環不退出,當沒有客戶端連接時,程序阻塞在accept上,有連接進來時才會往下執行,然后再次循環下去,為客戶端提供持久服務。

上面這個案例中,有兩個很大的缺陷:1.一次只可以為一個客戶端提供服務,如果正在為第一個客戶端發送helloworld期間有第二個客戶端來連接,那么第二個客戶端就必須要等待片刻才行。

2.很容易受到攻擊,造成拒絕服務。

分析了上述問題后,又聯想到了前面說的多進程,那我們可以在accpet到一個請求后就fork一個子進程來處理這個客戶端的請求,這樣當accept了第二個客戶端后再fork一個子進程來處理第二個客戶端的請求,這樣問題不就解決了嗎?OK!擼一把代碼演示一下:<?php

$host?=?'0.0.0.0';

$port?=?9999;

//?創建一個tcp?socket

$listen_socket?=?socket_create(?AF_INET,?SOCK_STREAM,?SOL_TCP?);

//?將socket?bind到IP:port上

socket_bind(?$listen_socket,?$host,?$port?);

//?開始監聽socket

socket_listen(?$listen_socket?);

//?進入while循環,不用擔心死循環死機,因為程序將會阻塞在下面的socket_accept()函數上

while(?true?){

//?此處將會阻塞住,一直到有客戶端來連接服務器。阻塞狀態的進程是不會占據CPU的

//?所以你不用擔心while循環會將機器拖垮,不會的

$connection_socket?=?socket_accept(?$listen_socket?);

//?當accept了新的客戶端連接后,就fork出一個子進程專門處理

$pid?=?pcntl_fork();

//?在子進程中處理當前連接的請求業務

if(?0?==?$pid?){

//?向客戶端發送一個helloworld

$msg?=?"helloworld

";

socket_write(?$connection_socket,?$msg,?strlen(?$msg?)?);

//?休眠5秒鐘,可以用來觀察時候可以同時為多個客戶端提供服務

echo?time().'?:?a?new?client'.PHP_EOL;

sleep(?5?);

socket_close(?$connection_socket?);

exit;

}

}

socket_close(?$listen_socket?);

將代碼保存為server.php,然后執行php server.php,客戶端依然使用telnet 127.0.0.1 9999,只不過這次我們開啟兩個終端來執行telnet。重點觀察當第一個客戶端連接上去后,第二個客戶端時候也可以連接上去。運行結果如下:

通過接受到客戶端請求的時間戳可以看到現在服務器可以同時為N個客戶端服務的。但是,接著想,如果先后有1萬個客戶端來請求呢?這個時候服務器會fork出1萬個子進程來處理每個客戶端連接,這是會死人的。fork本身就是一個很浪費系統資源的系統調用,1W次fork足以讓系統崩潰,即便當下系統承受住了1W次fork,那么fork出來的這1W個子進程也夠系統內存喝一壺了,最后是好不容易費勁fork出來的子進程在處理完畢當前客戶端后又被關閉了,下次請求還要重新fork,這本身就是一種浪費,不符合社會主義主流價值觀。如果是有人惡意攻擊,那么系統fork的數量還會呈直線上漲一直到系統崩潰。

所以,我們就再次提出增進型解決方案。我們可以預估一下業務量,然后在服務啟動的時候就fork出固定數量的子進程,每個子進程處于無限循環中并阻塞在accept上,當有客戶端連接擠進來就處理客戶請求,當處理完成后僅僅關閉連接但本身并不銷毀,而是繼續等待下一個客戶端的請求。這樣,不僅避免了進程反復fork銷毀巨大資源浪費,而且通過固定數量的子進程來保護系統不會因無限fork而崩潰。<?php

$host?=?'0.0.0.0';

$port?=?9999;

//?創建一個tcp?socket

$listen_socket?=?socket_create(?AF_INET,?SOCK_STREAM,?SOL_TCP?);

//?將socket?bind到IP:port上

socket_bind(?$listen_socket,?$host,?$port?);

//?開始監聽socket

socket_listen(?$listen_socket?);

//?給主進程換個名字

cli_set_process_title(?'phpserver?master?process'?);

//?按照數量fork出固定個數子進程

for(?$i?=?1;?$i?<=?10;?$i++?){

$pid?=?pcntl_fork();

if(?0?==?$pid?){

cli_set_process_title(?'phpserver?worker?process'?);

while(?true?){

$conn_socket?=?socket_accept(?$listen_socket?);

$msg?=?"helloworld

";

socket_write(?$conn_socket,?$msg,?strlen(?$msg?)?);

socket_close(?$conn_socket?);

}

}

}

//?主進程不可以退出,代碼演示比較粗暴,為了不保證退出直接走while循環,休眠一秒鐘

//?實際上,主進程真正該做的應該是收集子進程pid,監控各個子進程的狀態等等

while(?true?){

sleep(?1?);

}

socket_close(?$connection_socket?);

將文件保存為server.php后php server.php執行,然后再用ps -ef | grep phpserver | grep -v grep來看下服務器進程狀態:

可以看到master進程存在,除此之外還有10個子進程處于等待服務狀態,再同一個時刻可以同時為10個客戶端提供服務。我們通過telnet 127.0.0.1 9999來嘗試一下,運行結果如下圖:

總結

以上是生活随笔為你收集整理的php后端如何搭建socket服务,从php做一个简单的socket服务器流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。