热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用Easyswoole搭建简单的Websoket服务

步骤1修改配置文件MAIN_SERVER.SERVER_TYPE为EASYSWOOLE_WEB_SOCKET_SERVER如dev.php

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

如dev.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事件进行回调注册:

{$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

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解析器   

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

/** ws控制器测试**/namespace App\WebSocket\WSController;use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\Socket\AbstractInterface\Controller;class Index extends Controller {public function index() {$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']));}}public function index1(){var_dump('这里是index1');}}

步骤六  连接websoket  进行测试  

前端html 代码如下:


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

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

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

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

结果如图:

 


推荐阅读
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Python如何调用类里面的方法
    本文介绍了在Python中调用同一个类中的方法需要加上self参数,并且规范写法要求每个函数的第一个参数都为self。同时还介绍了如何调用另一个类中的方法。详细内容请阅读剩余部分。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
author-avatar
顾世嵐
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有