国产+高潮+在线,国产 av 仑乱内谢,www国产亚洲精品久久,51国产偷自视频区视频,成人午夜精品网站在线观看

workerman開發(fā)文檔

walkor

注意,這個是workerman老版本文檔,已經(jīng)不適用目前版本

workerman文檔最新地址 http://wtbis.cn/doc/workerman

一、workerman是什么

  workerman是一個高性能的PHP Socket服務器框架,它類似PHP-FPM,提供進程控制及socket通訊功能,區(qū)別是PHP-FPM是以FAST-CGI的協(xié)議對外提供服務的,而workerman卻可以支持各種協(xié)議(包括自定義協(xié)議),并且支持長鏈接,支持進程內全局對象資源等永久保持等特性。

二、workerman能做什么

  雖然workerman可以作為Webserver的替代Nginx PHP-FPM等架構,并且性能也比Nginx PHP-FPM高,但是我們不推薦這樣做,因為PHP的WebServer市場上已經(jīng)很成熟了,workerman不會再去做重復的事情。反而workerman把精力花在傳統(tǒng)WebServer無法勝任的角色上,例如非HTTP協(xié)議的應用、長鏈接應用、UDP應用、IM、游戲后端等。

三、workerman目錄結構

../
├── applications
└── workerman

  1、workerman目錄是workerman框架的核心代碼,包含了啟動腳本及workerman配置等。為了方便理解你可以把它看作PHP-FPM。
  2、applications目錄存放的是應用程序,例如應用框架、應用入口文件(類似index.php),業(yè)務邏輯等等。

workerman與applications是如何交互的
  workerman可以看作是PHP-FPM,所以它需要一個入口文件(類似index.php),這個入口文件可以放在applications中,這個入口文件一般滿足以下要求:
  1、繼承Man\Core\SocketWorker類
  2、實現(xiàn)Man\Core\SocketWorker::dealInput方法
  3、實現(xiàn)Man\Core\SocketWorker::dealProcess方法
workerman就是運行入口文件中的dealInput dealProcess方法來與業(yè)務銜接的。

四、workerman請求周期

  workerman請求周期包括了請求解析+業(yè)務處理兩部分,正好對應Man\Core\SocketWorker::dealInput/dealProcess兩個方法。也就是說客戶端每次請求一般都會調用Man\Core\SocketWorker::dealInput/dealProcess,這兩個方法也正是暴露給開發(fā)者的接口,實現(xiàn)這兩個接口使得開發(fā)者可以在請求到來時和請求接收完畢時加入自己的業(yè)務邏輯。下面詳細說明兩個方法。

Man\Core\SocketWorker::dealInput($recv_buffer)方法
  這個方法是用來根據(jù)應用層協(xié)議判斷從客戶端接收到的$recv_buffer數(shù)據(jù)是否合法、是否完整。這個方法的返回值有三種情況,X>0說明還有X字節(jié)沒有收到,X==0說明數(shù)據(jù)全部收到,進入業(yè)務處理階段dealProcess,X==false說明數(shù)據(jù)包格式錯誤

Man\Core\SocketWorker::dealProcess($recv_buffer)方法
  當Man\Core\SocketWorker::dealInput($recv_buffer)返回0時,即說明客戶端接收到的$recv_buffer是合法并完整的,這時根據(jù)應用層協(xié)議解析出實際的內容做相應的業(yè)務邏輯。

五、如何使用workerman

1、使用workerman第一步就是要確認你用哪種應用層協(xié)議。
什么是應用層協(xié)議?
  應用層協(xié)議是用來識別網(wǎng)絡傳來數(shù)據(jù)是否完整及傳輸?shù)臄?shù)據(jù)是什么,協(xié)議一般包括兩部分:
  1、數(shù)據(jù)完整性標記(Man\Core\SocketWorker::dealInput)。
  2、數(shù)據(jù)格式(Man\Core\SocketWorker::dealProcess)。
  不要把協(xié)議想象成是很復雜的東西,舉個例子應用層協(xié)議類似于有人給你郵寄過來一堆物品(網(wǎng)絡數(shù)據(jù)),你要判斷東西(數(shù)據(jù))是否都送來了,那么你就需要看下快遞清單(類似協(xié)議頭,里面記錄了數(shù)據(jù)長度),清單上寫著3個箱子,你看到確實有3個箱子,確認物品全部收到了(以上是Man\Core\SocketWorker::dealInput函數(shù)要做的事)。然后打開箱子(雙方協(xié)商的解包方法、json_decode、parse_xml等)便可以看到具體的物品(數(shù)據(jù))了,有了物品(數(shù)據(jù))你便可以做你應該做的事情了(這部分是Man\Core\SocketWorker::dealProcess做的事情)。

讓我們來定義一個應用層協(xié)議
1、數(shù)據(jù)完整性標識
  第一種:固定位置的一個字段標記整個包的長度。例如數(shù)據(jù)首部四個字節(jié)(int)是數(shù)據(jù)包長度+數(shù)據(jù),即$packed_int . $string
  第二種:在每一段數(shù)據(jù)結束時加上一個特粟的標記位,一般是一個字節(jié)。例如在數(shù)據(jù)末尾加上\0表示一個數(shù)據(jù)包結束,即$string.‘\0’
  當然還有其它方法
2、數(shù)據(jù)格式
  數(shù)據(jù)格式有很多選擇,如文本、json、xml、二進制流等等

一個協(xié)議的實現(xiàn) 4bytes+json, 即pack('N', $len).$json

創(chuàng)建文件 applications/JsonDemo/JsonProto.php

<?php
class JsonProto
{
    // 根據(jù)首部四個字節(jié)(int)判斷數(shù)據(jù)是否接收完畢
    public static function check($buffer)
    {
        // 讀取首部四個字節(jié)
        $buffer_data = unpack('Ntotal_length', $buffer);
        // 得到這次數(shù)據(jù)的整體長度(字節(jié))
        $total_length = $buffer_data['total_length'];
        // 已經(jīng)收到的長度(字節(jié))
        $recv_length = strlen($buffer);
        if($total_length>$recv_length)
        {
            // 還有這么多字節(jié)要接收
            return $total_length - $recv_length;
        }
        // 接收完畢
        return 0;
    }

    // 打包
    public static function encode($data)
    {
        // 選用json格式化數(shù)據(jù)
        $buffer = json_encode($data);
        // 包的整體長度為json長度加首部四個字節(jié)(首部數(shù)據(jù)包長度存儲占用空間)
        $total_length = 4 + strlen($buffer);
        return pack('N', $total_length) . $buffer;
    }

    // 解包
    public static function decode($buffer)
    {
        $buffer_data = unpack('Ntotal_length', $buffer);
        // 得到這次數(shù)據(jù)的整體長度(字節(jié))
        $total_length = $buffer_data['total_length'];
        // json的數(shù)據(jù)
        $json_string = substr($buffer, 4);
        return json_decode($json_string, true);
    }
} 

2、創(chuàng)建入口文件并實現(xiàn) Man\Core\SocketWorker::dealInput dealProcess方法
創(chuàng)建入口文件 applications/JsonDemo/JsonDemo.php

<?php
require_once __DIR__.'/JsonProto.php';
class JsonDemo extends Man\Core\SocketWorker
{
    // workeman 請求周期第一步,根據(jù)應用層協(xié)議判斷數(shù)據(jù)是否接收完畢
    public function dealInput($recv_buffer)
    {
        // 判斷數(shù)據(jù)是否接收完畢
        return JsonProto::check($recv_buffer); 
    }

    // workerman請求周期第二步,請求接收完畢后根據(jù)接收到的數(shù)據(jù)運行對應的業(yè)務邏輯
    public function dealProcess($recv_buffer)
    {
        // 得到json數(shù)據(jù)
        $json_data = JsonProto::decode($recv_buffer);

        /**
          *  這里根據(jù)你的json_data內容出處理不同的業(yè)務邏輯
         **/

        // 如果有需要,可以向客戶端發(fā)送結果
        $this->sendToClient(JsonProto::encode(array('code'=>0, 'msg'=>'ok')));
    }
}

3、配置workerman
創(chuàng)建配置 workerman/conf/conf.d/JsonDemo.conf,配置名與類名相同。

;進程入口文件,類似index.php
worker_file = ../applications/JsonDemo/JsonDemo.php
;監(jiān)聽的ip 端口,udp協(xié)議則是 listen=udp://0.0.0.0:2020
listen = tcp://0.0.0.0:2020
;你的網(wǎng)絡服務是長連接還是短連接。如果需要和客戶端一直保持鏈接(例如聊天類應用)則設置為1,否則設置為0
persistent_connection = 0
;啟動多少服務進程
start_workers=5
;以哪個用戶運行該進程,為了安全考錄,應該使用權限較低的用戶,例如www-data nobody等
user=root
;socket有數(shù)據(jù)可讀的時候預讀長度,一般設置為應用層協(xié)議包頭的長度,因為JsonProto首部四個字節(jié)標識了長度,所以這里設置為4
preread_length=4

六、啟動workerman

./workerman/bin/workermand start

至此你的服務框架已經(jīng)開發(fā)完了

七、寫一個簡單的PHP客戶端

<?php
require_once __DIR__.'/JsonProto.php';
$socket = stream_socket_client('tcp://127.0.0.1:2020');
// JsonDemo::dealInput 會收到 $recv_buffer 類似 xxxx{'mod':'abc','act':'cde'} 這樣的數(shù)據(jù),其中xxxx是四個字節(jié)的int數(shù)字,表現(xiàn)為亂碼,后面是json串
fwrite($socket, JsonProto::encode(array('mod'=>'abc', 'act'=>'cde')));
var_export(fread($socket, 65535));

八、關于進程模型

workerman整體的進程模型是master slave 模型:
  1、master進程負責監(jiān)控slave,slave進程退出時master進程會重新創(chuàng)建相同的slave進程
  2、slave進程是實際干活兒的進程,負責接收請求(Man\Core\SocketWorker::dealInput)以及處理請求(Man\Core\SocketWorker::dealProcess)

進程模型的變種
  workerman[b]整體[/b]的進程模型是master slave 模型,但是根據(jù)slave的工作不同,有一些區(qū)別,下面通過例子講解。
http://wtbis.cn/workerman 中有兩個例子,一個是FileRecevierDemo(二進制文件傳輸),一個是ChatDemo(聊天)。

FileRecevierDemo文件傳輸
  測試方法是啟動workerman后,命令行運行 cd applications/FileReceiverDemo/ ,命令行運行 php ClientDemo.php workerman.png 2 會把當前目錄的workerman.png 文件傳輸給workerman,然后workerman會把文件存儲到本地(邏輯在applications/FileReceiverDemo/FileReceiverDemo.php中),并且返回存儲位置,然后服務端和客戶端斷開鏈接。
FileRecevierDemo分析
  1、dealInput:所用協(xié)議 頭部5個字節(jié),前4個字節(jié)如上面JsonDemo一樣標識數(shù)據(jù)包長度,另外一個字節(jié)表示文件類型(1:jpg,2:png..),再后面緊接著是二進制圖片數(shù)據(jù)
  2、dealProcess:因為頭部固定5個字節(jié),則從第6個字節(jié)開始到包長的所有數(shù)據(jù)就是圖片數(shù)據(jù),截取完畢后根據(jù)頭部1個字節(jié)的文件類型(1:jpg、2:png..),保存文件到本地,并發(fā)給客戶端結果($this->sendToClient())

FileRecevierDemo進程模型
  FileRecevierDemo是典型的master slave進程模型,slave進程具有以下特點:
  1、slave既負責網(wǎng)絡傳輸,又負責業(yè)務處理
  2、短鏈接(業(yè)務處理完畢后就斷開鏈接,下次傳文件時會再次鏈接)

ChatDemo聊天
  測試方法:啟動workerman后,命令行運行 cd applications/ChatDemo/Tests,命令行運行 php Chat.php。打字回車發(fā)給所有人,uid:XXXXX發(fā)消息給某個人。

ChatDemo進程模型分析
  1、ChatDemo的slave進程分為兩種:gateway進程和worker進程
  2、gateway進程:applications/ChatDemo/Bootstrap/Gateway.php,這個進程只負責網(wǎng)路IO,不處理業(yè)務邏輯。具體工作內容為:維持服務端與客戶端的長鏈接,將客戶端的數(shù)據(jù)轉發(fā)給worker進程(目前是udp協(xié)議,有需要可以自行改成tcp),worker進程做實際的業(yè)務處理,有需要時將結果數(shù)據(jù)發(fā)給gateway進程(目前是udp協(xié)議,有需要可以自行改成tcp),gateway進程將結果數(shù)據(jù)轉發(fā)給對應的用戶。
  3、worker進程:applications/ChatDemo/Bootstrap/Worker.php,這個進程主要負責業(yè)務邏輯。具體工作內容為:負責接收gateway轉發(fā)來的客戶端請求,并解析處理,如果有需要,則同樣通過gateway向某個/些客戶端發(fā)送數(shù)據(jù)。

ChatDemo進程模型特點
  1、有兩個slave進程,一個負責網(wǎng)絡IO并維持客戶端鏈接,一個負責業(yè)務處理
  2、長鏈接,客戶端與gateway之間是TCP長鏈接,通過這個鏈接實現(xiàn)客戶端與服務端的雙向通信

九、為什么使用gateway worker模型

  gateway worker模型非常適合長鏈接應用,例如聊天、游戲后臺等。如果是短鏈接,則建議使用上面FileRecevierDemo基礎的master slave模型。
  1、gateway只負責網(wǎng)絡IO,worker主要負責業(yè)務邏輯。各司其職,非常高效。
  打個比方,一個餐館有4工人(進程),他們即負責招呼客人(網(wǎng)絡IO),又負責在廚房做菜(業(yè)務邏輯)。當客人一下子來很多的時候(很多鏈接或很多數(shù)據(jù)),大家有可能都去招待客人了(都處理網(wǎng)絡IO),廚房沒人做菜(做業(yè)務)。當大家都做菜的時候(做業(yè)務),又沒人招呼客人(接收鏈接),導致客人(用戶)都在等待。但是當我們把工人(進程)分工一下,2個人專門招呼客人(geteway進程),兩個人專門做菜(worker進程),這樣每個時刻都有有人(進程)招待客人(接收數(shù)據(jù)),都有人(進程)做菜(處理業(yè)務)。當gateway不夠用的時候(一般都是夠用的)增加gateway,worker忙不過來的時候增加worker進程。這樣效率會提升很多。
  2、提高穩(wěn)定性
  gateway進程因為要維持用戶鏈接,這要求gateway進程一定要非常穩(wěn)定,不然如果gateway進程出問題,則這個進程上的所有用戶都會斷開鏈接。讓gateway只負責網(wǎng)絡IO,不負責業(yè)務,就是因為業(yè)務頻繁變化,可能會有致命的錯誤(例如調用了一個不存在的函數(shù))導致進程退出,進而導致用戶鏈接斷開。而讓gateway只負責網(wǎng)絡IO,就是要避免這種風險。而worker進程是無狀態(tài)的(沒有保存用戶鏈接等狀態(tài)信息),即使偶爾出現(xiàn)FatalErr,也只會影響當前的這次請求,而不會對整個服務造成大的影響。
  3、熱更新
  由于gateway進程沒有業(yè)務邏輯,所以geteway進程極少有代碼更新。而worker進程由于負責業(yè)務邏輯,會有經(jīng)常性的代碼更新。這樣看來我們每次代碼更新,只要重啟worker進程就可以實現(xiàn)運行新的業(yè)務代碼。實際上也是這樣,當更新程序邏輯時,我們只需要重啟worker進程就可以了,這樣就不會導致更新代碼的時候用戶鏈接會斷開,達到不影響用戶的情況下熱更新后臺程序。
  4、擴展容易
  當worker進程不夠用的時候,我們可以水平擴展它,可增加worker的進程數(shù)量,甚至可以增加服務器專門運行worker進程,達到水平擴展的目的,以支持更大的用戶量。gateway進程也是同樣的道理。

十、gateway worker進程模型預留的接口

  正如上面所說,gateway worker模型非常適合長鏈接應用,為此ChatDemo專門抽象出來相應的接口以簡化長鏈接應用的開發(fā)。
使用ChatDemo中的gateway worker進程模型,業(yè)務開發(fā)者只需要實現(xiàn)worker進程中的業(yè)務邏輯即可,開發(fā)者只需要關注applications/ChatDemo/Event.php。這個文件開放了三個方法給開發(fā)者去實現(xiàn)。
  1、onConnect
  當用戶鏈接服務器后發(fā)的第一個數(shù)據(jù)包時會觸發(fā)這個方法,一般在這里做用戶登錄驗證工作,例如通過用戶傳來的$message($message是客戶端傳遞過來未作任何加工的原始數(shù)據(jù),里面一般包含了用戶名和密碼)獲得用戶名密碼,然后從數(shù)據(jù)庫中獲得uid(uid必須為大于0小于42億的數(shù)字),并存儲這個uid的內部gateway通信地址( GateWay::storeUid($uid)),還要向gateway進程注冊(GateWay::notifyConnectionSuccess($uid))這個uid,還可以在這里向數(shù)據(jù)庫中標記該用戶在線狀態(tài)。如果用戶不合法則可以調用GateWay::kickCurrentUser(‘’)踢掉當前登錄用戶。
  2、onMessage
  當合法用戶(onConnection時用戶合法并注冊)發(fā)來數(shù)據(jù)時會觸發(fā)這個方法。這個方法里面主要是處理業(yè)務邏輯。$message是客戶端發(fā)過來的未作任何加工的原始數(shù)據(jù),通過商定的協(xié)議去解析$message,然后根據(jù)數(shù)據(jù)內容做路由分發(fā),運行同的業(yè)務函數(shù)等。如果這期間需要給某uid或者所有人的客戶端發(fā)消息,則使用Gateway::sendToUid/SendToAll方法即可。
  3、onClose
  當用戶客戶端主動斷開時,觸發(fā)這個方法。
在這個方法中開發(fā)者可以清理用戶的數(shù)據(jù),例如在數(shù)據(jù)庫中加上下線標記。

發(fā)送數(shù)據(jù)接口
  chatDemo中提供了兩個給用戶客戶端發(fā)送數(shù)據(jù)的接口
  1、Gateway::sendToAll($message)
  這個是向所有在線的(當前鏈接服務器的)所有用戶發(fā)送消息。$message是要發(fā)送的數(shù)據(jù),客戶端會收到未經(jīng)過任何處理的原始$message數(shù)據(jù)??蛻舳耸盏竭@個$message數(shù)據(jù)后根據(jù)協(xié)議解析數(shù)據(jù)內容,做相應的展現(xiàn)。
  2、Gateway::sendToUid($uid, $message);
  向某個在線用戶的客戶端發(fā)送消息,$uid是接收者的uid。$message是要發(fā)送的數(shù)據(jù),目標用戶的客戶端會收到未經(jīng)過任何處理的原始$message數(shù)據(jù)??蛻舳耸盏竭@個$message數(shù)據(jù)后根據(jù)協(xié)議解析數(shù)據(jù)內容,做相應的展現(xiàn)。
  3、Gateway::kickUid/kickCurrentUid
  踢掉某uid用戶/當前用戶
  4、如何給某批(群組)的用戶發(fā)消息
  需要循環(huán)調用Gateway::sendToUid($uid, $message);方法

待續(xù).....

18469 1 1
1個評論

smith

nice!

  • 暫無評論
年代過于久遠,無法發(fā)表評論

walkor

163041
積分
0
獲贊數(shù)
0
粉絲數(shù)
2014-05-04 加入
??