LIBEVENT框架
此框架的擴充套件是LIBEVENT,php手冊地址libevent,該框架了封裝I/O事件,定時事件,中斷訊號事件,核心I/O複用函式支援EPOLL,POLL,SELECT,DEVPOLL,KQUEUE。框架官方網站libvent官網以下專案使用了該框架
框架涉及到的知識點說明【非常重要,否則可能會複製貼上跑起來了,但是相關知識點並沒有完全的理解,更談不上熟悉php擼的workerman框架了^_^】
- TCP/IP
- thread 執行緒
- I/O複用
- 事件處理模式
- reactor 模式
- Proactor 模式
- 併發模式
- 半同步/半非同步模式
- 定時器
- 中斷訊號
- I/O事件
- 事件多路分發器EventDeumultiplexer
- 事件處理器EventHandler
- 低層知識
- 網路卡驅動
- ARP協議【mac硬體實體地址交換】
- 網路資料幀
- 同步/非同步執行緒
本人註解的網路框架libevent原始碼核心原理分析
相關測試原始碼和分析流程以及筆記可聯絡本人獲取
原始碼框架安裝說明
如果認真看過PHP手冊的人安裝php擴充套件是非常容易的.
本人安裝的擴充套件是event2.2.1版本
執行個示例玩先
<?php
class MyListenerConnection {
private $bev, $base;
public function __destruct() {
//將讀寫和異常回撥清空同時釋放BufferEvent相關內建的資料
$this->bev->free();
}
public function __construct($base, $fd) {
$this->base = $base;
//建立BufferEvent物件
//此物件內建了讀寫事件處理器,但並沒有新增到I/O事件池中
//同時該物件分別建立input/outpu物件【內建建立】主要用於資料讀寫【接收和傳送】
$this->bev = new EventBufferEvent($base, $fd, EventBufferEvent::OPT_CLOSE_ON_FREE);
//設定讀寫異常回撥函式 【寫回撥並未設定】
$this->bev->setCallbacks(array($this, "echoReadCallback"), NULL,
array($this, "echoEventCallback"), NULL);
//將內建的寫事件處理器新增到I/O事件池中,並且向核心事件表註冊讀就緒事件
if (!$this->bev->enable(Event::READ)) {
echo "Failed to enable READ\n";
return;
}
}
public function echoReadCallback($bev, $ctx) {
//讀就緒事件發生後,內建的讀事件處理器執行,然後執行此函式
//同時呼叫output,並把input【內建的讀事件處理器讀取的資料會放入到此input物件中】
//直接將接受的資料寫入到客戶端
$bev->output->addBuffer($bev->input);
}
public function echoEventCallback($bev, $events, $ctx) {
//異常回撥
if ($events & EventBufferEvent::ERROR) {
echo "Error from bufferevent\n";
}
if ($events & (EventBufferEvent::EOF | EventBufferEvent::ERROR)) {
//$bev->free();
$this->__destruct();
}
}
}
class MyListener {
public $base, $listener, $socket;
private $conn = array();
public function __destruct() {
foreach ($this->conn as &$c) $c = NULL;
}
public function __construct($port) {
//建立event_base物件
//內建了I/O事件處理器池和訊號事件處理器池
//同時也內建的定時時間堆
$this->base = new EventBase();
if (!$this->base) {
echo "Couldn't open event base";
exit(1);
}
//建立socket 並監聽同時將此socket的讀就緒事件註冊到【經過I/O複用函式即事件多路分發器EventDemultiplexer管理】
//此socket 內建了監聽事件處理器,客戶端連線後,會呼叫此事件處理器,然後再執行使用者設定的回撥函式acceptConnCallBack函式
//EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE 標誌位
//EventListener::OPT_CLOSE_ON_FREE 此引數會關閉低層連線socket
//EventListener::OPT_REUSEABLE 和前面說過的socket 選項有關【不清楚請翻閱之前我寫過的東西】
//後面2個引數為ip和埠用於生成socket
$this->listener = new EventListener($this->base,
array($this, "acceptConnCallback"), $this->base,
EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1,
"0.0.0.0:$port");
if (!$this->listener) {
echo "Couldn't create listener";
exit(1);
}
//設定此socket事件處理器的錯誤回撥
$this->listener->setErrorCallback(array($this, "accept_error_cb"));
}
public function dispatch() {
//內建了event_base_loop進行迴圈處理
//主要是呼叫如epoll的epoll_wait函式進行監聽
//當任意I/O產生了就緒事件則會通知此程式
//此程式將會遍歷就緒的I/O事件讀取檔案描述符
//並從I/O事件處理器池讀取對應的事件處理器隊鏈
//再將事件處理器插入到請求佇列中
//兩從請求佇列中獲取到事件並迴圈一一處理
//從而執行指定的回撥函式
$this->base->dispatch();
}
/**
* @param $listener 上面的監聽器
* @param $fd 產生就緒事件的檔案描述符
* @param $address 客戶端地址
* @param $ctx 使用者自定義傳遞的引數
*/
public function acceptConnCallback($listener, $fd, $address, $ctx) {
$base = $this->base;
$this->conn[] = new MyListenerConnection($base, $fd);
}
public function accept_error_cb($listener, $ctx) {
$base = $this->base;
fprintf(STDERR, "Got an error %d (%s) on the listener. "
."Shutting down.\n",
EventUtil::getLastSocketErrno(),
EventUtil::getLastSocketError());
$base->exit(NULL);
}
}
$port = 12345;
if ($argc > 1) {
$port = (int) $argv[1];
}
if ($port <= 0 || $port > 65535) {
exit("Invalid port");
}
$l = new MyListener($port);
//event_base_loop持續阻塞
//直到核心事件表中的I/O事件就緒產生才會執行相就的回撥函式
$l->dispatch();
框架內部用到的資料結構和PHP關聯的物件
new EventBase() 對應c內部的event_base結構體
new EventListener 對應內部的evconnlistener結構體
new EventBufferEvent 對應內部的bufferevent結構體
更多相關的內容請閱讀本人註解的核心libevent框架,不然你可能對這些知識點感到燒腦子
本作品採用《CC 協議》,轉載必須註明作者和本文連結