使用Swoole能夠很簡單的搭建異步非阻塞多進程的WebSocket服務器。php
<?php $server = new swoole_websocket_server("0.0.0.0", 9501); $server->set(array( 'daemonize' => false, 'worker_num' => 2, )); $server->on('Start', function (swoole_websocket_server $server) { echo "Server Start... \n"; swoole_set_process_name("swoole_websocket_server"); }); $server->on('ManagerStart', function (swoole_websocket_server $server) { echo "ManagerStart\n"; }); $server->on('WorkerStart', function (swoole_websocket_server $server, $worker_id) { echo "WorkerStart \n"; if ($server->worker_id == 0){ swoole_timer_tick(10000,function($id) use ($server) { echo "test timer\n"; }); } }); $server->on('Open', function (swoole_websocket_server $server, $request) { echo "server: handshake success with fd{$request->fd}\n"; }); $server->on('Message', function (swoole_websocket_server $server, $frame) { echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n"; $server->push($frame->fd, "this is server"); }); $server->on('Close', function ($ser, $fd) { echo "client {$fd} closed\n"; }); $server->start();
shell裏直接運行php swoole_ws_server.php
啓動便可。若是設置了後臺運行,能夠使用下列命令強殺進程:html
kill -9 $(ps aux|grep swoole|grep -v grep|awk '{print $2}')
或者從新啓動worker進程:nginx
kill -10 $(ps aux|grep swoole_websocket_server|grep -v grep|awk '{print $2}')
輸出:git
[2017-06-01 22:06:21 $2479.0] NOTICE Server is reloading now. WorkerStart WorkerStart
注意:github
/** * @param $server * @param $frame 包含了客戶端發來的數據幀信息;使用$frame->fd獲取fd;$frame->data獲取數據內容 */ function onMessage(swoole_server $server, swoole_websocket_frame $frame)
$server->push()
向客戶端發送消息。長度最大不得超過2M。發送成功返回true,發送失敗返回false。function swoole_websocket_server->push(int $fd, string $data, int $opcode = 1, bool $finish = true);
最簡單的是使用JS編寫:web
socket = new WebSocket('ws://192.168.1.107:9501/'); socket.onopen = function(evt) { // 發送一個初始化消息 socket.send('I am the client and I\'m listening!'); }; // 監聽消息 socket.onmessage = function(event) { console.log('Client received a message', event); }; // 監聽Socket的關閉 socket.onclose = function(event) { console.log('Client notified socket has closed',event); }; socket.onerror = function(evt) { console.log('Client onerror',event); };
Swoole裏沒有直接提供swoole_websocket客戶端,不過經過引入WebSocketClient.php文件能夠實現:redis
<?php require_once __DIR__ . '/WebSocketClient.php'; $client = new WebSocketClient('192.168.1.107', 9501); if (!$client->connect()) { echo "connect failed \n"; return false; } $send_data = "I am client.\n"; if (!$client->send($send_data)) { echo $send_data. " send failed \n"; return false; } echo "send succ \n"; return true;
上面代碼實現的是一個同步的swoole_websocket客戶端。發送完消息會自動關閉,能夠用來與php-fpm應用協做:將耗時任務使用客戶端發送到swoole_websocket_server。shell
實際項目裏,咱們能夠將用戶uid和fd進行雙向綁定(暫不考慮多臺服務器分佈式部署狀況),例如使用Redis保存:在onMessage進行用戶信息驗證後:瀏覽器
$this->redis->set($fd, $uid); $this->redis->set($uid, $fd);
後續須要指定給某人發消息,只須要根據uid/fd發送便可。在onClose事件裏進行解綁操做。羣發的話只須要遍歷一遍$server->connections
便可。服務器
示例(該項目只實現羣發):
moell-peng/webim: PHP + Swoole 實現的簡單聊天室
https://github.com/moell-peng...
swoole內置Http服務器的支持。swoole版的http server相對於php-fpm,最大優點在於高性能:代碼一次載入內存,後續無需再解釋執行。缺點是調試沒有nginx+php-fpm方便。
使用swoole,經過幾行代碼便可寫出一個異步非阻塞多進程的Http服務器:
<?php $serv = new swoole_http_server("0.0.0.0", 9502); $serv->on('Start', function() { echo 'Start'; }); $serv->on('Request', function($request, $response) { var_dump($request->get); var_dump($request->post); var_dump($request->cookie); var_dump($request->files); var_dump($request->header); var_dump($request->server); $response->cookie("User", "Swoole"); $response->header("X-Server", "Swoole"); $response->end("<h1>Hello Swoole!</h1>"); }); $serv->start();
shell裏使用php swoole_http_server.php
運行server。瀏覽器打開http://192.168.1.107:9502/便可看到輸出。
歡迎關注公衆號及時獲取最新文章推送!