將 Socket 服務(wù)器運(yùn)行于多線程環(huán)境中

2018-06-21 15:45 更新

很多人存在誤解,認(rèn)為 PHP 不支持多線程,實(shí)際上,是支持的,只是默認(rèn)情況下,PHP 安裝包中并不包含多線程擴(kuò)展,需要自己到?PHP 擴(kuò)展社區(qū)庫(kù)(PECL)網(wǎng)站上下載,鏈接為?http://pecl.php.net/package/pthreads。如果是?Windows 用戶,也可以在點(diǎn)擊這個(gè)鏈接進(jìn)行下載:http://windows.php.net/downloads/pecl/releases/pthreads/。

多線程有很多好處,也不只可以用于 Socket 通訊,但是,由于 Socket 領(lǐng)域更有可能需要多線程,這篇文章只講述如何讓 ModPHP 的 Socket 服務(wù)器能力在多線程上得到體現(xiàn)。

假設(shè)你安裝了多線程的 PHP 環(huán)境,并且對(duì)其有了一定的了解,如果沒(méi)有,請(qǐng)自行到 PHP 官網(wǎng)上進(jìn)行學(xué)習(xí)。

ModPHP 的 Socket 服務(wù)器要想運(yùn)行在多線程中,其實(shí)很簡(jiǎn)單,當(dāng)然你需要將 ModPHP 更新為 1.8.4 版本或者更新(如果有)。下面這段代碼是 2.0.1 版本中 socket-server-thread.php 文件中實(shí)現(xiàn)多線程Socket 服務(wù)器的代碼,你可以直接使用或者參考它編寫(xiě)更出色的程序邏輯:

<?php 
if(!class_exists('Thread')){
    fwrite(STDOUT, "PHP does not support multi-threading yet.\n");
    goto console;
}
include 'mod/classes/socket-server.class.php'; //引入 WebSocket 擴(kuò)展
/** 監(jiān)聽(tīng)端口 */
$server = SocketServer::listen(@$_SERVER['argv'][1] ?: 8080, function($server, $port){
    fwrite(STDOUT, "Socket server $server started on $port at ".date('m-d-Y H:i:s').".\n");
}, false); //將第三個(gè)參數(shù)($autoStart)設(shè)置為 false
/** 創(chuàng)建線程類(lèi) */
class SocketServerThread extends Thread{
    /** 將服務(wù)器資源傳入線程作用域 */
    function __construct($server){
        $this->server = $server;
    }

 
    function run(){
        SocketServer::server($this->server); //設(shè)置服務(wù)器
        include 'socket-server.php'; //引入 Socket 服務(wù)
        SocketServer::start(); //開(kāi)啟服務(wù)
    }
}
$threads = array(); //線程組
/** 創(chuàng)建若干個(gè)線程并加入線程組 */
for ($i=0; $i < (@$_SERVER['argv'][2] ?: 5); $i++) {
    $threads[$i] = new SocketServerThread($server);
    $threads[$i]->start();
}
/** 引入交互式控制臺(tái),可以監(jiān)控線程組 */
console:
include 'mod.php';

因?yàn)?PHP 的多線程擴(kuò)展是線程安全的,所以你基本上不用考慮線程直間會(huì)互相干預(yù),它們是完全獨(dú)立的(與其他語(yǔ)言不同)。但也由于這樣,PHP 程序的子線程的運(yùn)行級(jí)別要比存粹的 PHP 程序更低,因此它里面可能會(huì)出現(xiàn)某些無(wú)法預(yù)料的情況,如某些常量未定義,即使在主線程中這些常量是可用的。ModPHP 默認(rèn)提供了幾個(gè)在子線程中缺失的 PHP 內(nèi)置常量,因此這個(gè)問(wèn)題也并不是很重要。

還有一點(diǎn)就是,在上述代碼中,無(wú)法使用文件鎖,這可能是 pthreads 擴(kuò)展的 BUG,或者專(zhuān)門(mén)這么設(shè)計(jì)。解決的辦法是,在引入的交互式控制臺(tái)中,輸入并運(yùn)行 PHP 代碼,以此來(lái)啟用文件鎖。比如,你應(yīng)該在啟用 Socket 服務(wù)器之后,鎖定站點(diǎn)根目錄下的 .socket-server 文件,從而告知所有網(wǎng)站程序 Socket 服務(wù)器已啟動(dòng),例如 ModCMS 中,就是通過(guò)判斷 .socket-server 文件是否被鎖定來(lái)判斷是否開(kāi)啟了 Socket 服務(wù)器。

你可以在交互式控制臺(tái)中通過(guò)下面的代碼來(lái)鎖定 .socket-server 文件:

$file = fopen('.socket-server', 'r');
echo flock($file, LOCK_EX | LOCK_NB) ? 'File locked.' : 'Lock failed.';
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)