<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                IO 多路復用的 epoll 利器,epoll 是高性能程序的根基。PHP 中如何將 Socket 與 Event 結合使用的案例。這里的 Event 可以理解為是對 epoll 的高度封裝,底層采用的就是 epoll 利器 這段代碼就是提煉了 Workerman 對事件循環的實現原理。stream\_socket\_server 函數把創建、綁定、監聽一并實現了,讓代碼顯得更加簡潔,不像之前的 socket\_create、socket\_bind、socket\_listen 搞了三個步驟略顯繁瑣。 因為使用了事件循環,所以需要對 Socket 設置成非阻塞模式,只有當有讀或寫的通知時才會調用相應的回調函數。還有一點需要額外注意的,需要針對客戶端 Socket 創建的 Event 需要定義成靜態變量或全局變量,不然無法持久化連接到內存,會造成客戶端無法建立連接傳輸數據,我看到網上很多人都踩到了這個坑上。最后啟動事件循環 EventLoop 自此開啟了 Socket 監聽和事件循環雙操作 函數參考/其它服務/[Event](https://www.php.net/manual/zh/book.event.php) 函數參考/其它基本擴展/Stream/[Stream 函數](https://www.php.net/manual/zh/ref.stream.php) ``` // 創建 TCP 服務器套接字 $server = stream_socket_server("tcp://0.0.0.0:8080", $errno, $error); echo "正在監聽 8080 端口...". PHP_EOL; // 設置為非阻塞,在 $server 對象沒有數據可以讀取或寫入時不會阻塞其執行 stream_set_blocking($server, 0); // 創建事件基礎對象 $event_base = new EventBase(); // 建立事件監聽服務端 Socket 可讀事件 public Event::__construct( EventBase $base ,//要關聯的事件庫 mixed $fd ,//流資源、套接字資源或數字文件描述符。計時器事件傳遞-1。對于信號事件,請傳遞信號編號,例如SIGHUP。 int $what ,//事件標志。請參閱Event flags callable $cb ,//事件回調。查看Event callbacks mixed $arg = NULL//自定義數據。如果指定,它將在事件觸發時傳遞給回調 ); $event = new Event($event_base, $server, Event::READ | Event::PERSIST, function ($server) use ($event_base) { // 獲取新的連接,由于設置了非阻塞模式,那么這里即使沒有新的連接,也不會一直阻塞在這 $client = @stream_socket_accept($server, 0); if ($client) { echo "客戶端(" . $client . ")連接建立". PHP_EOL; // 針對客戶端過來的連接,也要設置成非阻塞模式 stream_set_blocking($client, 0); // 客戶端連接創建監聽可讀事件 // 這里需要特別注意:客戶端事件需要定義成靜態變量或全局變量 static $client_event; $client_event = new Event($event_base, $client, Event::READ | Event::PERSIST, function ($client) { // 從客戶端連接中讀取數據,每次只讀取 1024 字節數據 $buffer = fread($client, 1024); // 如果沒有讀取到數據或者客戶端已經不是資源句柄,則關閉客戶端連接 if ($buffer == false || !is_resource($client)) { // 關閉客戶端連接 fclose($client); echo "客戶端(" . $client . ")連接關閉" . PHP_EOL; return; } echo "收到客戶端(" . $client . ")數據: $buffer" . PHP_EOL; // 回寫數據給客戶端 $msg = "HTTP/1.0 200 OK\r\nContent-Length: 10\r\n\r\nServerOK\r\n"; fwrite($client, $msg); }, $client); $client_event->add(); } }, $server); // 添加事件 $event->add(); // 執行事件循環(上面設置非阻塞模式,只有當socket讀取或寫入時觸發回調函數) $event_base->loop(); ``` 使用 CURL 工具訪問http://127.0.0.1:8080便能正確返回結果 ServerOK 這表明事件循環可以進入正常運行狀態。 ~~~ Copy[manongsen@root php_event]$ curl -i http://127.0.0.1:8080 HTTP/1.0 200 OK Content-Length: 10 ServerOK ~~~ 下面這段代碼是引至 Workerman 的示例,通過 Worker 類構造了一個 HTTP 服務。onMessage 參數定義了一個回調函數,當有事件通知時,會回調到此處,之后就是用戶自行實現后續的處理邏輯了。runAll 函數會整體啟動整個服務,其中包括進程的創建、事件的循環等 ~~~ // 引用 Worker 類 use Workerman\Worker; // 自動加載 Composer require_once __DIR__ . '/vendor/autoload.php'; // 定義 HTTP 服務并監聽 8081 端口 $http_worker = new Worker('http://0.0.0.0:8081'); // 定義回調函數 $http_worker->onMessage = function ($connection, $request) { //$request->get(); //$request->post(); //$request->header(); //$request->cookie(); //$request->session(); //$request->uri(); //$request->path(); //$request->method(); // Send data to client $connection->send("Hello World"); }; // 啟動服務 Worker::runAll(); ~~~ 在 Worker.php 文件的 2367 行,使用 stream\_socket\_server 函數創建了服務端 Socket 并且綁定、監聽了 8081 端口。 ~~~ Copy// workerman/Worker.php:2367 $this->_mainSocket = \stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); ~~~ 在 Worker.php 文件的 2394 行,使用 stream\_set\_blocking 函數將 服務端 Socket 設置成非阻塞模式。 ~~~ Copy// workerman/Worker.php:2394 \stream_set_blocking($this->_mainSocket, false); ~~~ 在 Worker.php 文件的 2417 行,將服務端的 \_mainSocket 添加到事件循序中,并且設置回調函數為 acceptConnection 。 ~~~ Copy// workerman/Worker.php:2417 static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); ~~~ 在 Worker.php 文件的 2561 行,使用 stream\_socket\_accept 接收到來自客戶端的連接 $new\_socket ,其中這個操作是在 acceptConnection 回到函數中所進行的。 ~~~ Copy// workerman/Worker.php:2561 $new_socket = \stream_socket_accept($socket, 0, $remote_address); ~~~ 在 TcpConnection.php 文件的 285 行,使用 stream\_set\_blocking 函數將客戶端的 \_socket 設置成非阻塞模式,這里的 \_socket 和上面的 new\_socket 是同一個。 ~~~ Copy// workerman/Connection/TcpConnection.php:285 \stream_set_blocking($this->_socket, 0); ~~~ 在 TcpConnection.php 文件的 290 行,將客戶端的 \_socket 添加到事件循環中,并且設置其的回調函數為 baseRead 。 ~~~ Copy// workerman/Connection/TcpConnection.php:290 Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead')); ~~~ 在 Worker.php 文件的 1638 行,啟動事件循環。 ~~~ Copy// workerman/Worker.php:1638 static::$globalEvent->loop(); ~~~ 啟動事件循環后,當有客戶端連接時便可以讀取數據了。因此在 TcpConnection.php 文件的 583 行,使用 fread 函數讀取客戶端 $socket 的數據。 ~~~ Copy// workerman/Connection/TcpConnection.php:583 $buffer = @\fread($socket, self::READ_BUFFER_SIZE); ~~~ 在 TcpConnection.php 文件的 647 行,使用 parser::decode 函數將上面讀取到的 buffer 數據解析成 $request 對象,還有 $this 表示的是 $connection 對象,這個 $this->onMessage 是最開始用戶自定義的回調函數。最終通過 call\_user\_func 函數,將 $connection、$request 參數回調到 onMessage 方法。 ~~~ Copy// workerman/Connection/TcpConnection.php:647 \call_user_func($this->onMessage, $this, $parser::decode($one_request_buffer, $this)); ~~~ 最后我們使用 CURL 工具調用一下[http://127.0.0.1:8081](http://127.0.0.1:8081/)通過返回的數據,可以看出正確的回調到了 onMessage 函數。 ~~~ Copy[manongsen@root workerman]$ curl -i http://127.0.0.1:8081 HTTP/1.1 200 OK Server: workerman Connection: keep-alive Content-Type: text/html;charset=utf-8 Content-Length: 13 Hello World ~~~ 看到這里相信你已經對 Workerman 源碼中的事件循環有些了解了,如果有時間最好能夠實踐下最開始的那段案例代碼,然后再結合著看 Workerman 的源代碼會頗有收獲。Workerman 的高性能是站在了巨人 epoll 的肩膀上來實現,沒有了 epoll 則啥也不是。這里再重申一下 PHP 中的 Event 是對 epoll 的封裝,epoll 是 Linux 的底層技術。我們在日常的編程中是不會直接接觸到 epoll 的,最后回歸一下主題 epoll 技術才是 Workerman 的立命之本 [這才是 PHP 高性能框架 Workerman 的立命之本 - Yxh\_blogs - 博客園](https://www.cnblogs.com/yxhblogs/p/18319851)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看