当前位置: 首页 > news >正文

使用Easyswoole 搭建简单的Websoket服务

步骤1   修改配置文件MAIN_SERVER.SERVER_TYPEEASYSWOOLE_WEB_SOCKET_SERVER  

如dev.php

<?php
use EasySwoole\Log\LoggerInterface;return ['SERVER_NAME'=>"EasySwoole",'MAIN_SERVER'=>['LISTEN_ADDRESS'=>'0.0.0.0','PORT'=>'19501',"SERVER_TYPE"=>EASYSWOOLE_WEB_SOCKET_SERVER,  //可选为 EASYSWOOLE_SERVER  EASYSWOOLE_WEB_SERVER   EASYSWOOLE_WEB_SOCKET_SERRVER "SOCK_TYPE"=>SWOOLE_TCP,"RUN_MODEL"=>SWOOLE_PROCESS,"SETTING"=>['worker_num'=>8,'reload_async'=>true,'max_wait_time'=>3,'package_max_length'=>1024*1024*1024,'max_connection'=>150000,'socket_buffer_size'=>1024*1024*1024],],
];

步骤2  EasySwooleEvent中mainServerCreate事件进行回调注册:

<?phppublic static function mainServerCreate(\EasySwoole\EasySwoole\Swoole\EventRegister $register)
{$config = new \EasySwoole\Socket\Config();$config->setType($config::WEB_SOCKET);$config->setParser(WebSocketParser::class);$dispatcher = new Dispatcher($config);$config->setOnExceptionHandler(function (\Swoole\Server $server, \Throwable $throwable, string $raw, WebSocket $client, Response $response) {$response->setMessage('system error!');$response->setStatus($response::STATUS_RESPONSE_AND_CLOSE);});// 自定义握手/*$websocketEvent = new WebSocketEvent();$register->set(EventRegister::onHandShake, function (\Swoole\Http\Request $request, \Swoole\Http\Response $response) use ($websocketEvent) {$websocketEvent->onHandShake($request, $response);});*/$register->set($register::onMessage, function (\Swoole\Websocket\Server $server, \Swoole\Websocket\Frame $frame) use ($dispatcher) {$dispatcher->dispatch($server, $frame->data, $frame);});//注册服务时间$register->add(EventRegister::onOpen,[WebSocketEvents::class,'onOpen']);$register->add(EventRegister::onClose,[WebSocketEvents::class,'onClose']);}

步骤3  WebSocketEvents.php

<?phpnamespace App\WebSocket;use EasySwoole\MysqliPool\Mysql;
use EasySwoole\Mysqli\Config as MysqlConfig;
use EasySwoole\RedisPool\Config as RedisConfig;
use EasySwoole\RedisPool\Redis;
use EasySwoole\FastCache\Cache;
use SebastianBergmann\CodeCoverage\Report\PHP;class WebSocketEvents {//监听ws连接事件public static function onOpen(\swoole_websocket_server $server, \swoole_http_request $request) {echo $request->fd . '链接成功' . PHP_EOL;//return true;}//监听ws关闭事件public static function onClose(\swoole_server $server, int $fd, int $reactorId) {//echo $reactorId . ' -- ' . $fd . ' websocket 关闭' . PHP_EOL;//return true;}/*** @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'];}// 发送验证后的headerforeach ($headers as $key => $val) {$response->header($key, $val);}// 接受握手 还需要101状态码以切换状态$response->status(101);var_dump('shake success at fd :' . $request->fd);return true;}
}

步骤4  websocket解析器   

<?phpnamespace App\WebSocket;use EasySwoole\Socket\AbstractInterface\ParserInterface;
use EasySwoole\Socket\Client\WebSocket;
use EasySwoole\Socket\Bean\Caller;
use EasySwoole\Socket\Bean\Response;/*** Class WebSocketParser** 此类是自定义的 websocket 消息解析器* 此处使用的设计是使用 json string 作为消息格式* 当客户端消息到达服务端时,会调用 decode 方法进行消息解析* 会将 websocket 消息 转成具体的 Class -> Action 调用 并且将参数注入** @package App\WebSocket*/
class WebSocketParser implements ParserInterface {/*** decode* @param string $raw 客户端原始消息* @param WebSocket $client WebSocket Client 对象* @return Caller         Socket  调用对象*/public function decode($raw, $client): ?Caller {// new 调用者对象$caller = new Caller();// 解析 客户端原始消息$data = json_decode($raw, true);if (!is_array($data)) {echo "decode message error1111! \n";return null;}/*** 设置被调用的类 这里会将ws消息中的 class 参数解析为具体想访问的控制器* 如果更喜欢 event 方式 可以自定义 event 和具体的类的 map 即可* 注 目前 easyswoole 3.0.4 版本及以下 不支持直接传递 class string 可以通过这种方式*/$class = '\\App\\WebSocket\\WSController\\' . ucfirst($data['class'] ?? 'Index');$caller->setControllerClass($class);$action = $data['action'];$caller->setAction($action);// 检查是否存在args$args = isset($data['params']) && !empty($data['params']) ? $data['params'] : [];// 设置被调用的Args$caller->setArgs($args ?? []);return $caller;}/*** encode* @param Response $response Socket Response 对象* @param WebSocket $client WebSocket Client 对象* @return string             发送给客户端的消息*/public function encode(Response $response, $client): ?string {/*** 这里返回响应给客户端的信息* 这里应当只做统一的encode操作 具体的状态等应当由 Controller处理*/return $response->getMessage();}}

步骤五 新增Websoket 控制器   Index.php

App\WebSocket\WSController

<?php
/** ws控制器测试**/namespace App\WebSocket\WSController;use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\Socket\AbstractInterface\Controller;class Index1 extends Controller {public function index1() {$client = $this->caller()->getClient();$server = ServerManager::getInstance()->getSwooleServer();$post_info = $this->caller()->getArgs();if ($server->getClientInfo($client->getFd())) {$server->push($client->getFd(), json_encode(['data' => 'success']));}}}

步骤六  连接websoket  进行测试  

前端html 代码如下:

<!DOCTYPE html><html><head><title>测试</title></head><body><script type="text/javascript">ws = new WebSocket("ws://127.0.0.1:19501") ws.open = function () {alert('success')str = '{"class":"Index1","action":"index1","params":[]}'console.log(str)ws.send(str)}ws.onmessage = function (evt) {alert(evt.data)}ws.onclose = function (evt) {console.log('colose')}</script></body></html>
</html>

注: 其中发送的数据   JSON字符串    {"class":"Index1","action":"index1","params":[]}

class 表示请求到对应的Websoket控制器  

action 标识请求到对应的Websoket方法

params 为发送的数据,这里必须数组  若为其他,可能接收不到!

结果如图:

http://www.xdnf.cn/news/840169.html

相关文章:

  • 【年度总结】互联网不行了?对IT技术行业的深度思考
  • Visual Studio 2017 : client version 1.22 is too old
  • 初识Lazarus和Free Pascal Compiler
  • OS X10.10.3正式版和Xcode 6.3正式版下载
  • 计算机u盘设备无法启动不了,系统提示“该设备无法启动(代码:10)”,USB设备不能开始工作怎么办?...
  • Android基础入门
  • 中文乱码另类解决办法,简单,方便!
  • 详解RS-485上下拉电阻的选择
  • 意甲官网在中国地区被假网劫持,竟声称赞助?
  • 全球电容生产厂商排名一览表
  • 从Java角度看区块链实践系列4:从区块结构的“链”结构结构以及Merkle树,什么是软硬分叉?
  • Java武林q传仙女下凡_请问谁有武林Q传之仙女下凡的秘笈
  • 微信开放平台生态系列(一)微信第三方平台开发定制服务商模式配置
  • 电视常用接口(TV,AV,S-Video,YCbCr/PCbCr,VGA,Scart,DVI/HDMI)
  • 思维1
  • 19个免费的ppt制作网站
  • 名人博客大全
  • 我的闲鱼Python爬虫接单总结和经验,最高600!
  • IP归属地查询API详解
  • Excel表格的35招必学秘技
  • SSP对DSP发出的Bid Request应该包含什么信息
  • 很色,非常色,十分色,格外色,异常色,特别色,相当色,太色了!
  • 操作系统Marking02源代码
  • Windows 7互联网视频介绍
  • 大众文化与文化产业
  • 【保姆级教程】免费内网穿透,手把手搭建,三步搞定
  • GPT版超级马里奥来了!输入文本即可自定义游戏关卡 | GitHub标星500+
  • 155款安卓开源项目源码整理,总有你要找的(精心收集)
  • Android界面特效全汇总
  • 2014中秋节,用java为QQ游戏美女找茬写辅助