添加文件
- App/WebSocket/Index.php
- App/WebSocket/WebSocketEvent.php
- App/WebSocket/WebSocketParser.php
- EasySwooleEvent.php
修改文件
Index.php
| <?php |
| namespace App\WebSocket; |
| |
| use EasySwoole\EasySwoole\ServerManager; |
| use EasySwoole\EasySwoole\Task\TaskManager; |
| use EasySwoole\Socket\AbstractInterface\Controller; |
| |
| |
| |
| |
| |
| |
| |
| |
| class Index extends Controller |
| { |
| public function hello() |
| { |
| $this->response()->setMessage('call hello with arg:'.json_encode($this->caller()->getArgs())); |
| } |
| |
| public function who() |
| { |
| $this->response()->setMessage('your fd is '.$this->caller()->getClient()->getFd()); |
| } |
| |
| public function index() |
| { |
| |
| |
| |
| |
| |
| |
| |
| |
| print_r($this->caller()->getArgs()); |
| |
| echo PHP_EOL; |
| |
| |
| } |
| |
| public function delay() |
| { |
| $this->response()->setMessage('this is delay action'); |
| $client = $this->caller()->getClient(); |
| |
| |
| TaskManager::getInstance()->async(function () use ($client) { |
| |
| $server = ServerManager::getInstance()->getSwooleServer(); |
| |
| $i = 0; |
| |
| while ($i < 5) { |
| sleep(1); |
| $server->push($client->getFd(), 'push in http at '.date('H:i:s')); |
| $i++; |
| } |
| }); |
| } |
| |
| |
| |
| |
| |
| public function push() |
| { |
| $fd = $this->request()->getRequestParam('fd'); |
| |
| if (is_numeric($fd)) { |
| |
| $server = ServerManager::getInstance()->getSwooleServer(); |
| $info = $server->getClientInfo($fd); |
| |
| if ($info && $info['websocket_status'] === WEBSOCKET_STATUS_FRAME) { |
| $server->push($fd, 'http push to fd '.$fd.' at '.date('H:i:s')); |
| } else { |
| $this->response()->write("fd {$fd} is not exist or closed"); |
| } |
| } else { |
| $this->response()->write("fd {$fd} is invalid"); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| public function broadcast() |
| { |
| |
| $server = ServerManager::getInstance()->getSwooleServer(); |
| $start = 0; |
| |
| |
| |
| while (true) { |
| $conn_list = $server->connection_list($start, 10); |
| |
| if (empty($conn_list)) { |
| break; |
| } |
| |
| $start = end($conn_list); |
| |
| foreach ($conn_list as $fd) { |
| $info = $server->getClientInfo($fd); |
| |
| |
| if ($info && $info['websocket_status'] == WEBSOCKET_STATUS_FRAME) { |
| $server->push($fd, 'http broadcast fd '.$fd.' at '.date('H:i:s')); |
| } |
| } |
| } |
| } |
| } |
WebSocketEvent.php
| <?php |
| namespace App\WebSocket; |
| |
| use swoole_http_request; |
| use swoole_http_response; |
| |
| |
| |
| |
| |
| |
| |
| |
| class WebSocketEvent |
| { |
| |
| |
| |
| |
| |
| |
| |
| public function onHandShake(swoole_http_request $request, swoole_http_response $response) |
| { |
| |
| if (!$this->customHandShake($request, $response)) { |
| $response->end(); |
| |
| return false; |
| } |
| |
| if ($this->secWebsocketAccept($request, $response)) { |
| $response->end(); |
| |
| return true; |
| } |
| $response->end(); |
| |
| return false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function customHandShake(swoole_http_request $request, swoole_http_response $response): bool |
| { |
| |
| |
| |
| |
| |
| $headers = $request->header; |
| $cookie = $request->cookie; |
| |
| |
| |
| return true; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| public function onClose(\swoole_server $server, int $fd, int $reactorId) |
| { |
| |
| $info = $server->getClientInfo($fd); |
| |
| print_r($info); |
| |
| |
| |
| |
| |
| if ($info && $info['websocket_status'] === WEBSOCKET_STATUS_FRAME) { |
| |
| |
| |
| |
| if ($reactorId < 0) { |
| echo "server close \n"; |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function secWebsocketAccept(swoole_http_request $request, swoole_http_response $response): bool |
| { |
| |
| if (!isset($request->header['sec-websocket-key'])) { |
| |
| var_dump('shake fai1 3'); |
| |
| return false; |
| } |
| |
| if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key']) |
| || 16 !== strlen(base64_decode($request->header['sec-websocket-key'])) |
| ) { |
| |
| |
| return false; |
| } |
| |
| $key = base64_encode(sha1($request->header['sec-websocket-key'].'258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); |
| |
| $headers = array( |
| 'Upgrade' => 'websocket', |
| 'Connection' => 'Upgrade', |
| 'Sec-WebSocket-Accept' => $key, |
| 'Sec-WebSocket-Version' => '13', |
| 'KeepAlive' => 'off', |
| ); |
| |
| if (isset($request->header['sec-websocket-protocol'])) { |
| $headers['Sec-WebSocket-Protocol'] = $request->header['sec-websocket-protocol']; |
| } |
| |
| |
| foreach ($headers as $key => $val) { |
| $response->header($key, $val); |
| } |
| |
| |
| $response->status(101); |
| |
| |
| |
| return true; |
| } |
| } |
WebSocketParser.php
| <?php |
| namespace App\WebSocket; |
| |
| use EasySwoole\Socket\AbstractInterface\ParserInterface; |
| use EasySwoole\Socket\Client\WebSocket; |
| use EasySwoole\Socket\Bean\Caller; |
| use EasySwoole\Socket\Bean\Response; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class WebSocketParser implements ParserInterface |
| { |
| |
| |
| |
| |
| |
| |
| public function decode($raw, $client): ?Caller |
| { |
| |
| try { |
| $data = json_decode($raw, true, 512, JSON_THROW_ON_ERROR); |
| } catch (\JsonException $e) { |
| echo "decode message error! \n"; |
| |
| return null; |
| } |
| |
| |
| $caller = new Caller(); |
| |
| |
| |
| |
| |
| |
| $class = '\\App\\WebSocket\\'.ucfirst($data['class'] ?? 'Index'); |
| |
| $caller->setControllerClass($class); |
| |
| |
| $caller->setAction($data['action'] ?? 'index'); |
| |
| |
| if (!empty($data['params'])) { |
| |
| $args = is_array($data['params']) ? $data['params'] : ['params' => $data['params']]; |
| } |
| |
| |
| $caller->setArgs($args ?? []); |
| |
| return $caller; |
| } |
| |
| |
| |
| |
| |
| |
| |
| public function encode(Response $response, $client): ?string |
| { |
| |
| |
| |
| |
| return $response->getMessage(); |
| } |
| } |
EasySwooleEvent.php
| <?php |
| namespace EasySwoole\EasySwoole; |
| |
| use App\WebSocket\WebSocketParser; |
| use EasySwoole\EasySwoole\AbstractInterface\Event; |
| use EasySwoole\EasySwoole\Swoole\EventRegister; |
| use EasySwoole\Http\Request; |
| use EasySwoole\Http\Response; |
| use EasySwoole\Socket\Dispatcher; |
| use App\WebSocket\WebSocketEvent; |
| |
| class EasySwooleEvent implements Event |
| { |
| public static function initialize() |
| { |
| date_default_timezone_set('Asia/Shanghai'); |
| } |
| |
| public static function mainServerCreate(EventRegister $register): void |
| { |
| |
| $conf = new \EasySwoole\Socket\Config(); |
| |
| |
| $conf->setType(\EasySwoole\Socket\Config::WEB_SOCKET); |
| |
| |
| $conf->setParser(new WebSocketParser()); |
| |
| |
| $dispatch = new Dispatcher($conf); |
| |
| |
| $register->set(EventRegister::onMessage, |
| function (\swoole_websocket_server $server, \swoole_websocket_frame $frame) use ($dispatch) { |
| |
| $dispatch->dispatch($server, $frame->data, $frame); |
| |
| }); |
| |
| |
| $websocketEvent = new WebSocketEvent(); |
| |
| |
| $register->set(EventRegister::onClose, |
| function (\swoole_server $server, int $fd, int $reactorId) use ($websocketEvent) { |
| $websocketEvent->onClose($server, $fd, $reactorId); |
| }); |
| } |
| |
| public static function onRequest(Request $request, Response $response): bool |
| { |
| |
| return true; |
| } |
| |
| public static function afterRequest(Request $request, Response $response): void |
| { |
| |
| } |
| } |
验证
www.easyswoole.com/wstool.html
请求 Body:
{"class":"Index","action":"index","params":{"name":"hello"}}
来源
www.css3er.com/p/251.html