背景最近在一些项目中,需要用到Websocket实时推送给群组用户。前端需要向后端传输的信息相对较少。经过多方考虑,我们选择通过GatewayWorker框架(基于Workerman)来构建。微服务。Workerman简介Workerman是一个纯PHP开发的开源高性能PHP套接字服务框架。工人不是在重新发明轮子。它不是一个MVC框架,而是一个更底层、更通用的socket服务框架。你可以用它来开发tcp代理,天梯代理,游戏服务器,邮件服务器,ftp服务器,甚至可以开发一个php版本的php版本的redis,php版本的数据库,php版本的nginx,phpphp版本的-fpm等Workerman可以说是PHP领域的一次革新,让开发者彻底摆脱PHP只能做WEB的束缚。其实Workerman类似于一个PHP版的nginx,核心也是多进程+Epoll+非阻塞IO。Workerman的每个进程都可以保持上万个并发连接。由于是常驻内存,不依赖Apache、nginx、php-fpm等容器,具有超高性能。同时支持TCP、UDP、UNIXSOCKET,支持长连接,支持Websocket、HTTP、WSS、HTTPS等通信协议,以及各种自定义协议。拥有定时器、异步socket客户端、异步Mysql、异步Redis、异步Http、异步消息队列等众多高性能组件。github地址:https://github.com/walkor/Workerman文档:http://doc.workerman.net/315110GatewayWorkerGatewayWorker是基于Workerman开发的一个项目框架,用于快速开发TCP长连接应用,如作为应用推送服务器、InstantIM服务器、游戏服务器、物联网、智能家居等。GatewayWorker使用经典的Gateway和Worker进程模型。Gateway进程负责维护客户端连接,并将客户端的数据转发给BusinessWorker进程进行处理。BusinessWorker进程负责处理实际的业务逻辑(默认调用Events.php处理业务)并将结果推送给相应的客户端。Gateway服务和BusinessWorker服务可以分别部署在不同的服务器上,实现分布式集群。GatewayWorker提供了一个非常方便的API,可以全局广播数据,也可以向某个群组广播数据,或者向特定客户端推送数据。配合Workerman的定时器,也可以定时推送数据。github地址:https://github.com/walkor/GatewayWorker文档:http://doc2.workerman.net/326102Workerman与GatewayWorker的关系Workerman可以看作是一个纯socket库,可以开发几乎所有的网络应用,不管是TCP还是UDP,长连接还是短连接。Workerman代码精简、强大、灵活,可以快速开发各种网络应用。同时Workerman也比GatewayWorker更底层,需要开发者有一定的多进程编程经验。因为大部分开发者的目标是基于Workerman开发TCP长连接应用,而长连接应用服务器有很多共同点,比如它们有相同的单发、群发、广播等进程模型和接口需求.这就是有GatewayWorker框架的原因。GatewayWorker是基于Workerman开发的TCP长连接框架,实现了单发、群发、广播等长连接的必要接口。GatewayWorker框架实现了GatewayWorker进程模型,天然支持分布式多服务器部署。扩缩容非常方便,可以处理海量并发连接。可以说GatewayWorker是一个基于Workerman实现TCP长连接的比较完善的项目框架。GatewayClientGatewayClient是GatewayWorker的客户端程序,可以进行推送、分组、统计等操作。websocket微服务介绍了一般原则。websocket微服务不处理业务逻辑,只是一种单向连接,只负责推送信息。但是当客户端连接到websocket微服务时,websocket微服务返回clientId给客户端,客户端调用接口将clientId传递给后端。这时后台可以通过GatewayClient将用户绑定到特定的群组。但是当需要推送时,它通过文本协议与GatewayWorker通信,将要推送的clientId或group传给GatewayWorker,GatewayWorker再推送给客户端。示意图如下:具体实现安装GatewayWorker内核并新建一个空白项目(不是在Laravel/Lumen/ThinkPHP等PHP框架下),执行composerrequireworkerman/gateway-worker启动文件并新建一个根目录下的start.php作为启动文件,代码:name='business-gateway';//网关进程号$gateway->count=2;//localip,分布式部署使用内网ip$gateway->lanIp='127.0.0.1';//内部通信起始端口,如果$gateway->count=4,起始端口为4000//一般使用40004001400240034个端口作为内部通信端口$gateway->startPort=2900;//服务注册地址(注册类地址)$gateway->registerAddress='127.0.0.1:1238';注册BusinessWorker类BusinessWorker是运行业务逻辑当BusinessWorker收到Gateway转发的事件和请求时,会默认调用Events.php中的onConnectonMessageonClose方法处理事件和数据。开发人员通过实现这些回调来控制业务和流程。src/start_businessworker.php代码:name='Steam-BusinessWorker';//bussinessWorker进程数$worker->count=1;//服务注册地址$worker->registerAddress='127.0.0.1:1238';EventsEvents类用于捕获GatewayWorker的事件,这里可以写一些回调信息。src/Events.php代码:$client_id,]));}/***当客户端发送消息时触发*@paramint$client_idconnectionid*@parammixed$message具体消息*/publicstaticfunctiononMessage($client_id,$message){}/***当用户触发disconnects*@paramint$client_idconnectionid*/publicstaticfunctiononClose($client_id){}}在PHP项目中分组或推送到客户端。这是你自己项目中写的代码。流程:前端调用接口传递clientId,后端绑定群组。然后将信息推送到群或指定clientIdclient需要引用GatewayClient包composerrequireworkerman/gatewayclient代码在项目中://GatewayClient3.0.0之后添加了namespaceuseGatewayClient\Gateway;/***===指定registerAddress表示是哪个GatewayWorker(集群)它与通信有关。===*GatewayWorker中使用Register服务来区分集群,即一个GatewayWorker(集群)只有一个Register服务,*GatewayClient必须知道Register服务的地址才能与之通信,地址格式为ip:port,*其中ip为Register服务运行的ip(若单机部署GatewayWorker则为运行GatewayWorker的服务器ip),*port为对应服务器上start_register.php文件中监听的端口到ip,就是GatewayWorker启动时看到的Register的端口。*GatewayClient如果要向客户端推送数据,必须知道客户端位于哪个GatewayWorker(集群)。*然后连接到GatewayWorker(集群)的ip:端口注册服务,与对应的GatewayWorker(集群)通信.*此ip:port在GatewayClient端使用Gateway::$registerAddress指定。**===如果GatewayClient和GatewayWorker不在同一台服务器上,则需要执行以下步骤===*1.需要在start_gateway中设置lanIp。),设置完成后重启GatewayWorker*2.这里填写GatewayClient中Gateway::$registerAddress的ip,填写上一步指定的ip1lanIp,port*3.需要开启GatewayWorker所在服务器的防火墙位于,这样GatewayClientServer访问可以使用以下端口,*端口包括Rgister服务的端口和start_gateway.php中lanIp和startPort指定的几个端口**===如果GatewayClient和GatewayWorker在同一台服务器上===*GatewayClient和Register服务在一台服务器上,填写127.0.0.1和ip,其他不需要设置。**/Gateway::$registerAddress='127.0.0.1:1236';//GatewayClient支持GatewayWorker中的所有接口(Gateway::closeCurrentClientGateway::sendToCurrentClient除外)Gateway::sendToAll($data);Gateway::sendToClient($client_id,$data);Gateway::closeClient($client_id);Gateway::isOnline($client_id);Gateway::bindUid($client_id,$uid);Gateway::isUidOnline($uid);网关::getClientIdByUid($client_id);Gateway::unbindUid($client_id,$uid);Gateway::sendToUid($uid,$dat);Gateway::joinGroup($client_id,$group);Gateway::sendToGroup($group,$data);Gateway::leaveGroup($client_id,$group);Gateway::getClientCountByGroup($group);Gateway::getClientSessionsByGroup($group);Gateway::getAllClientCount();Gateway::getAllClientSessions();网关::setSession($client_id,$session);Gateway::updateSession($client_id,$session);Gateway::getSession($client_id);译文:https://www.wugenglong.com/We...
