安裝步驟如下(推薦把安裝文件下載到 /usr/local/src 目錄下): step 1: wget --no-check-certificate https://github.com/swoole/swoole-src/archive/v1.9.13.tar.gz step 2: tar zxf v1.9.13.tar.gz step 3: cd swoole-src-1.9.13 step 4: phpize step 5: ./configure --with-php-config=/usr/local/php/bin/php-config step 6: make && make install step 7: 修改 php.ini ,加入 extension=swoole.so ,然后重啟 php-fpm step 8: 執行 php --info | grep swoole 查看設置是否生效 ############################ 消費者,文件名《server.php》 ############################ <?php class Server { private $serv; private $logFile; public function __construct() { $this->serv = new swoole_server('0.0.0.0', 9501); // 允許所有IP訪問 $this->serv->set([ 'worker_num' => 4, // 一般設置為服務器CPU數的1-4倍 'task_worker_num' => 1, // task進程的數量(一般任務都是同步阻塞的,可以設置為多進程單線程) 'daemonize' => true, // 以守護進程執行 'package_eof' => PHP_EOL, // 設置EOF 'open_eof_split' => true, // 按照EOF進行分包,防止TCP粘包 'max_request' => 5000, // 設置worker進程的最大任務數,軟重啟,防止可能存在的內存溢出 'task_max_request' => 5000, // 設置Task線程的最大任務數,軟重啟,防止可能存在的內存溢出 // 'task_ipc_mode' => 1, // 使用unix socket通信,默認模式 // 'log_file' => '/data/log/queue.log' , // swoole日志 // 數據包分發策略(dispatch_mode=1/3時,底層會屏蔽onConnect/onClose事件, // 原因是這2種模式下無法保證onConnect/onClose/onReceive的順序,非請求響應式的服務器程序,請不要使用模式1或3) // 'dispatch_mode' => 2, // 固定模式,根據連接的文件描述符分配worker。這樣可以保證同一個連接發來的數據只會被同一個worker處理 ]); $this->logFile = dirname(__FILE__).'/log.txt'; // 以守護進程執行的時候,要絕對路徑 $this->serv->on('Receive', [$this, 'onReceive']); $this->serv->on('Task', [$this, 'onTask']); $this->serv->on('Finish', [$this, 'onFinish']); $this->serv->start(); } /** * 接收到數據時回調此函數,發生在worker進程中 * $server,swoole_server對象 * $fd,TCP客戶端連接的文件描述符 * $from_id,TCP連接所在的Reactor線程ID * $data,收到的數據內容,可能是文本或者二進制內容 */ public function onReceive($serv, $fd, $from_id, $data ) { $str = "=========== onReceive ============ \n"; $str .= "Get Message From Client $fd:$data \n"; error_log($str, 3, $this->logFile); $serv->task( $data ); } /** * 在task_worker進程內被調用。worker進程可以使用swoole_server_task函數向task_worker進程投遞新的任務。當前的Task進程在調用onTask回調函數時會將進程狀態切換為忙碌, * 這時將不再接收新的Task,當onTask函數返回時會將進程狀態切換為空閑然后繼續接收新的Task。 * $task_id是任務ID,由swoole擴展內自動生成,用於區分不同的任務。$task_id和$src_worker_id組合起來才是全局唯一的,不同的worker進程投遞的任務ID可能會有相同 * $src_worker_id來自於哪個worker進程 * $data 是任務的內容 */ public function onTask($serv, $task_id, $src_worker_id, $data) { $data = trim($data); // 刪除EOF $array = json_decode( $data , true ); $str = "=========== onTask ============ \n"; $str .= var_export($array, 1); error_log($str, 3 , $this->logFile); return $array; } /** * 當worker進程投遞的任務在task_worker中完成時,task進程會通過swoole_server->finish()方法將任務處理的結果發送給worker進程 * $task_id是任務的ID * $data是任務處理的結果內容(也就是onTask()函數,中return的值) */ public function onFinish($serv, $task_id, $data) { $str = "=========== onFinish ============ \n"; $str .= "Task $task_id finish ! \n"; $str .= var_export($data, 1); error_log($str, 3, $this->logFile); } } $server = new Server(); ############################ 生產者,文件名《client.php》 ############################ <?php class Client { private function _sendData($data) { // dispatch_mode=2, 固定模式,根據連接的文件描述符分配worker // 每次都要重新new ,不可做成單例(這樣才有不同的連接文件描述符,進而有不同的task_id) $client = new \swoole_client(SWOOLE_SOCK_TCP); $client->connect('127.0.0.1', 9501, 1); // 發送數據包,一定要在最后指明斷行(防止“粘包”),一般值 PHP_EOL ,與配置參數package_eof的值保持一致 $client->send($data.PHP_EOL); } public function run() { for($i=0; $i<10; $i++) { $data = [ 'time' => rand(1000, 9999), 'id' => $i ]; $jsonData = json_encode($data); $this->_sendData($jsonData); } } } ############################ 華麗的分割線 ############################ 先執行 php server.php (執行一次,會以守護進程運行) 然后再執行 php client.php # 內核參數調整(關鍵步驟) http://wiki.swoole.com/wiki/page/p-server/sysctl.html # swoole 離線手冊,里面有更多的示例 https://github.com/smalleyes/swoole-chm