安装
composer require easyswoole/socket
1、根目录dev.php
EASYSWOOLE_WEB_SERVER 改成 EASYSWOOLE_WEB_SOCKET_SERVER
2、在App新建WebSocket目录
3、在WebSocket里新建WebSocketParser.php
<?php
namespace App\WebSocket;//目录
use EasySwoole\Socket\AbstractInterface\ParserInterface;
use EasySwoole\Socket\Bean\Caller;
use EasySwoole\Socket\Bean\Response;
class WebSocketParser implements ParserInterface
{
public function decode($raw, $client): ?Caller
{
$data = json_decode($raw, true);
$caller = new Caller();
$controller = !empty($data['controller']) ? $data['controller'] : 'Index';
$action = !empty($data['action']) ? $data['action'] : 'index';
$param = !empty($data['param']) ? $data['param'] : [];
$controller = "App\\WebSocket\\Controller\\{$controller}";//控制器路径
$caller->setControllerClass($controller);
$caller->setAction($action);
$caller->setArgs($param);
return $caller;
}
public function encode(Response $response, $client): ?string
{
return json_encode($response->getMessage());
}
}
4、在WebSocket新建Controller目录,在Controller新建Index.php文件控制器
<?php
namespace App\WebSocket\Controller;//目录
use EasySwoole\Socket\AbstractInterface\Controller;
use EasySwoole\EasySwoole\ServerManager;//给其他fd发送数据
class Index extends Controller
{
public function index()
{
$dade = $this->caller()->getClient();//获得全部
$fd = $dade->getFd();//握手的fd
$dades = $this->caller()->getArgs();//获得setArgs数据
//给其他接口发送数据
$server = ServerManager::getInstance()->getSwooleServer();
$server->push($fd, 6666);
$this->response()->setMessage('大得大得');
}
}
5、EasySwooleEvent.php文件中
引入use App\WebSocket\WebSocketParser;
然后mainServerCreate方法加入
$config = new \EasySwoole\Socket\Config();
$config->setType($config::WEB_SOCKET);
$config->setParser(WebSocketParser::class);
$dispatcher = new \EasySwoole\Socket\Dispatcher($config);
$config->setOnExceptionHandler(function (\Swoole\Server $server, \Throwable $throwable, string $raw, \EasySwoole\Socket\Client\WebSocket $client, \EasySwoole\Socket\Bean\Response $response) {
$response->setMessage('system error!');
$response->setStatus($response::STATUS_RESPONSE_AND_CLOSE);
});
$register->set($register::onMessage, function (\Swoole\Websocket\Server $server, \Swoole\Websocket\Frame $frame) use ($dispatcher) {
$dispatcher->dispatch($server, $frame->data, $frame);
});
$register->set($register::onClose,function (){
var_dump('关闭了');
});
vue
mounted(){
let _this = this
var wsServer = 'ws://域名:9501';
_this.websocket = new WebSocket(wsServer);
_this.websocket.onopen = function (evt) {
console.log("连接成功");
//发送数据
//发送数据
var data = {'controller':'Index','action':'index','param':{'id':33}};
_this.websocket.send(JSON.stringify(data))
};
_this.websocket.onclose = function (evt) {
console.log("关闭");
};
_this.websocket.onmessage = function (evt) {
console.log('数据: ' + JSON.parse(evt.data));
};
_this.websocket.onerror = function (evt, e) {
console.log('错误: ' + evt.data);
};
},
//页面销毁时关闭长连接
destroyed() {
this.websocket.close();
},
另外如果使用自定义握手
在WebSocket创建WebSocketEvents.php
mainServerCreate修改
public static function mainServerCreate(EventRegister $register)
{
$config = new \EasySwoole\Socket\Config();
$config->setType($config::WEB_SOCKET);
$config->setParser(WebSocketParser::class);
$dispatcher = new \EasySwoole\Socket\Dispatcher($config);
$config->setOnExceptionHandler(function (\Swoole\Server $server, \Throwable $throwable, string $raw, \EasySwoole\Socket\Client\WebSocket $client, \EasySwoole\Socket\Bean\Response $response) {
$response->setMessage('system error!');
$response->setStatus($response::STATUS_RESPONSE_AND_CLOSE);
});
// 自定义握手(onOpen)
$websocketEvent = new WebSocketEvents();
$register->set(EventRegister::onHandShake, function (\Swoole\Http\Request $request, \Swoole\Http\Response $response) use ($websocketEvent) {
$websocketEvent->onHandShake($request, $response);
});
//注册事件(关闭)
$register->add(EventRegister::onClose, [WebSocketEvents::class, 'onClose']);
$register->set($register::onMessage, function (\Swoole\Websocket\Server $server, \Swoole\Websocket\Frame $frame) use ($dispatcher) {
$dispatcher->dispatch($server, $frame->data, $frame);
});
}
WebSocketEvents.php内容
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2022/5/2
* Time: 9:19
*/
namespace App\WebSocket;
class WebSocketEvents
{
/**
* @param \Swoole\Http\Request $request
* @param \Swoole\Http\Response $response
* @return bool
*/
public function onHandShake(\Swoole\Http\Request $request, \Swoole\Http\Response $response)
{
/** 此处自定义握手规则 返回 false 时中止握手 */
if (!$this->customHandShake($request, $response)) {
$response->end();
return false;
}
/** 此处是 RFC规范中的WebSocket握手验证过程 必须执行 否则无法正确握手 */
if ($this->secWebsocketAccept($request, $response)) {
$response->end();
return true;
}
$response->end();
return false;
}
/**
* @param \Swoole\Http\Request $request
* @param \Swoole\Http\Response $response
* @return bool
*/
protected function customHandShake(\Swoole\Http\Request $request, \Swoole\Http\Response $response): bool
{
/**
* 这里可以通过 http request 获取到相应的数据
* 进行自定义验证后即可
* (注) 浏览器中 JavaScript 并不支持自定义握手请求头 只能选择别的方式 如get参数
*/
$headers = $request->header;
$cookie = $request->cookie;
// if (如果不满足我某些自定义的需求条件,返回false,握手失败) {
// return false;
// }
return true;
}
/**
* RFC规范中的WebSocket握手验证过程
* 以下内容必须强制使用
*
* @param \Swoole\Http\Request $request
* @param \Swoole\Http\Response $response
* @return bool
*/
protected function secWebsocketAccept(\Swoole\Http\Request $request, \Swoole\Http\Response $response): bool
{
// ws rfc 规范中约定的验证过程
if (!isset($request->header['sec-websocket-key'])) {
// 需要 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']))
) {
//不接受握手
var_dump('shake fai1 4');
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'];
}
// 发送验证后的header
foreach ($headers as $key => $val) {
$response->header($key, $val);
}
// 接受握手 还需要101状态码以切换状态
$response->status(101);
var_dump('连接成功 :' . $request->fd);
return true;
}
/**
* 连接关闭
* */
public static function onClose(\Swoole\Server $server, int $fd, int $reactorId)
{
$info = $server->connection_info($fd);
var_dump("关闭-了$fd");
}
}
|