Thinkphp5.0 安装使用Workerman实现websocket前后端通信,后端主动推送消息到前端

这篇具有很好参考价值的文章主要介绍了Thinkphp5.0 安装使用Workerman实现websocket前后端通信,后端主动推送消息到前端。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

安装使用Workerman实现websocket前后端通信,后端主动推送消息到前端,实现后端有数据更新时,前端页面自动更新数据。
我使用的是基于Thinkphp5.0的ThinkCMF5.0。
安装:

composer require topthink/think-worker=v1.0.1

启动:

php server.php start -d

public目录下放置的server.php文件,注意里面的配置必须按照你的Worker控制器来:

#!/usr/bin/env php
<?php
// 调试模式开关
define("APP_DEBUG", false);
// 定义 APP 命名空间
define("APP_NAMESPACE", 'api');
// 定义CMF根目录,可更改此目录
define('CMF_ROOT', __DIR__ . '/../');
// 定义应用目录
define('APP_PATH', CMF_ROOT . 'api/');
// 定义CMF目录
define('CMF_PATH', CMF_ROOT . 'simplewind/cmf/');
// 定义网站入口目录
define('WEB_ROOT', __DIR__ . '/');
// 定义插件目录
define('PLUGINS_PATH', __DIR__ . '/plugins/');
// 定义扩展目录
define('EXTEND_PATH', CMF_ROOT . 'simplewind/extend/');
define('VENDOR_PATH', CMF_ROOT . 'simplewind/vendor/');
// 定义应用的运行时目录
define('RUNTIME_PATH',__DIR__.'/../data/runtime/api/');
//define('APP_PATH', __DIR__ . '/api/');
define('BIND_MODULE','user/Worker');
// 加载框架引导文件
require __DIR__ . '/../simplewind/thinkphp/start.php';

woker控制器:

<?php

namespace api\user\controller;
use think\Db;
use think\worker\Server;
use Workerman\Worker;
use Workerman\Lib\Timer;

class WorkerController extends Server
{
    protected $socket = 'websocket://0.0.0.0:2346';
    protected $uidConnections = [];
    protected $HEARTBEAT_TIME = '60';
    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $datas)
    {
            $connection->lastMessageTime = time();
            $data = json_decode($datas);
            if (empty($data->uid)) {
                $connection->close();
                return;
            }
            $uid = 1;//这里的uid根据自己的情况去验证
            if (empty($uid)) {
                $connection->close();
                return;
            }
            switch ($data->type) {
                case 'login':
                    // 保存该用户的输送数据
                    $this->uidConnections[$uid] = $connection;
                    // $connection->send('发送成功');
                    break;
                case 'send':
                    // 发送消息
                    // $this->sendMessageByUid($uid, $datas);
                    break;
            }
    }

    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
    {
         $connection->send('链接成功');
    }

    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
    {
        if(isset($connection->uid))
        {
            // 连接断开时删除映射
            unset($this->uidConnections[$connection->uid]);
        }
    }

    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo "error $code $msg\n";
    }

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
        // 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符
        $inner_text_worker = new Worker('text://0.0.0.0:2347');
//        $inner_text_worker->reusePort=true;
        $inner_text_worker->onMessage = function ($connection, $buffer) {
            // $data数组格式,里面有uid,表示向那个uid的页面推送数据
            $data = json_decode($buffer, true);
            $uid = $data['uid'];
            // 通过workerman,向uid的页面推送数据
            $ret = $this->sendMessageByUid($uid, $buffer);
            // 返回推送结果
            $connection->send($ret ? 'ok' : 'fail');
        };
        // ## 执行监听 ##
        $inner_text_worker->listen();
        Timer::add(10, function()use($worker){
            $time_now = time();
            foreach($worker->connections as $connection) {
                // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
                if (empty($connection->lastMessageTime)) {
                    $connection->lastMessageTime = $time_now;
                    continue;
                }
//                $diff_time = $time_now - $connection->lastMessageTime;
//                $msg = '距离上次通话已经过去'.$diff_time.'秒';
//                $connection->send($msg);
                // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
                if ($time_now - $connection->lastMessageTime > $this->HEARTBEAT_TIME) {
                    $connection->close();
                }
            }
        });
    }

    // 向所有验证的用户推送数据
    public function broadcast($message)
    {
        foreach($this->uidConnections as $connection)
        {
            $connection->send($message);
        }
    }

    // 针对uid推送数据
    public function sendMessageByUid($uid, $message)
    {
        if(isset($this->uidConnections[$uid]))
        {
            $connection = $this->uidConnections[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }
}

后端主动推送到前端:

$client = stream_socket_client('tcp://127.0.0.1:2347', $errno, $errmsg, 1);
// 推送的数据,包含uid字段,表示是给这个uid推送
$data_sock = array('uid'=>$merchant, 'type'=>'update');
// 发送数据,Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($data_sock)."\n");
// 读取推送结果
// echo fread($client, 8192);

前端代码:

socketStart() {
        var uid = localStorage.getItem('token')
        var socket = new WebSocket('wss://www.yechai.com/wss')
        // 打开Socket
        socket.onopen = (event) => {
          socket.send(
            JSON.stringify({
              type: 'login',
              uid: uid,
            })
          )
        }
        socket.onmessage = (event) => {
          if (event.data.indexOf('update') != -1) this.fetchData() //收到更新命令,前端更新
          // console.log('receive', event.data)
        }

        // 监听Socket的关闭
        socket.onclose = (event) => {
          console.log('close', event)
          setTimeout(() => {
            this.socketStart()
          }, 50000)
        }

        socket.onerror = function (e) {
          console.log(e)
        }

        this.socket = socket
      },
      socketSend() {
        var uid = localStorage.getItem('token')
        this.socket.send(
          JSON.stringify({
            type: 'send',
            uid: uid,
          })
        )
      },

Nginx配置:

 location /wss {
        proxy_pass http://1.1.1.1:2346;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 180s;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 5000M;
    }

因为主动推送的关系,进程数设置为1:
\vendor\topthink\think-worker\src\Server.php

protected $processes = 1;

为什么?
例如:客户端1连接进程A,客户端2连接进程B,客户端2无法直接通过进程B给客户端1发送数据,因为客户端1属于进程A不属于进程B,B进程控制不到客户端1(要想两个进程之间通讯需要一些进程间通讯手段,可以使用http://doc3.workerman.net/component/channel.html)。所以所有客户端都只能连接同一个进程才能直接互相通讯,为了避免客户端连到不同进程,count设置为1。文章来源地址https://www.toymoban.com/news/detail-599405.html

到了这里,关于Thinkphp5.0 安装使用Workerman实现websocket前后端通信,后端主动推送消息到前端的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用 PHP WorkerMan 构建 WebSocket 全双工群聊通信(二)

    在很早很早以前,WebSocket 协议还没有被发明的时候,人们在 Web 端制作类实时数据动态更新时,一般采用轮询、 长连接 (Long Polling) 来实现。大概就是: 轮询:客户端不停发送 HTTP 请求给服务端,服务端返回最新数据 长连接:客户端发送一条 HTTP 请求给服务端,服务端 HOLD

    2024年02月09日
    浏览(36)
  • 使用Docker Dockerfile构建php LNMP集成开发环境,并运行Thinkphp5

    系统:MAC、Windows10 Docker版本:Docker version 23.0.5 Docker Desktop:Dockerdesktop官方地址 这篇主要介绍如何在Mac、Windows10使用docker搭建LNMP集成开发环境。下面我会写Dockerfile编译安装Nginx+php基础环境。mysql、redis基于官方Docker hub,分别构建我们自己的镜像。  code目录存放工程代码,会映

    2024年02月15日
    浏览(58)
  • 基于微信小程序的在线考试的设计与实现 后台Thinkphp5+MySql(附源码 论文 配置 讲解)

    摘要 本文详细介绍了一个基于微信小程序的在线考试系统的设计与实现。该系统提供了注册账号,在线考试,和考试记录模块等功能,方便用户进行在线考试和查看考试记录。前端采用微信开发者工具开发,后端使用ThinkPHP5框架进行实现。本文详细阐述了该系统的设计思路、

    2024年02月05日
    浏览(74)
  • thinkphp6和thinkphp5有什么区别

    Thinkphp6.0完全开发手册 采用PHP7强类型(严格模式) tp5 环境要求PHP = 5.4.0 ThinkPHP6.0的环境要求 PHP = 7.2.5 6.0版本开始,必须通过Composer方式安装和更新,所以你无法通过Git下载安装。 支持更多的PSR规范 V6.0.10版本开始 支持 psr7 response 多应用支持 tp5默认使用多应用模式部署 tp6 安

    2024年02月06日
    浏览(58)
  • thinkphp5拦截验证token

    写一个BaseController 类 基本思路: 1、继承一个公共基类,将验证相关代码放在基类 2、根据 孩子类下的notNeedToken 来决定是否进行验证 3、验证失败后,直接响应回来 这里需要封装一个主要代码: 如果直接return 返回,是不会终止执行的,而是会继续执行到指定的控制器,所以

    2024年02月15日
    浏览(44)
  • thinkPhp5返回某些指定字段

    或者指定要的字段的数组  查询符合条件的多条数据  

    2024年02月09日
    浏览(45)
  • ThinkPHP5远程命令执行漏洞

    ThinkPHP是一个快速、兼容而且简单的轻量级国产 PHP开发框架 ,诞生于2006年初,原名FCS,2007年元旦正式更名为ThinkPHP,遵循Apache2开源协议发布,使用面向对象的开发结构和 MVC模式 ,从Struts结构移植过来并做了改进和完善,同时也借鉴了国外很多优秀的框架和模式。 由于th

    2024年02月11日
    浏览(47)
  • Thinkphp5.x全漏洞复现分析

    我们可以把namespace理解为一个单独的空间,事实上它也就是一个空间而已,子命名空间那就是空间里再划分几个小空间,举个例子: 当有多个子命名空间有相同名称类时,不指定使用哪个命名空间的情况下取最后定义的命名空间中的类,比如上面的 dog 取的时 dogC 中的类,在

    2024年04月22日
    浏览(45)
  • ThinkPHP5.0.23 远程代码执行漏洞

    ThinkPHP 是一款运用极广的 PHP 开发框架。其 5.0.23 以前的版本中,获取 method 的方法中没有正确处理方法名,导致攻击者可以调用 Request 类任意方法并构造利用链,从而导致远程代码执行漏洞。 百度漏洞 获得exp 路径: POST传参 我用的是hackbar,用burpsuite也行。 burp操作方法 抓包

    2024年02月11日
    浏览(45)
  • ThinkPHP5.0.21远程命令执行漏洞

    漏洞出现的背景 : ThinkPHP是⼀款运⽤极⼴的PHP开发框架。 其5.0.23以前的版本中,获取method的⽅法中没有正确处理⽅法名, 导致攻击者可以调⽤Request类任意⽅法并构造利⽤链,从⽽导致远程代码执⾏漏洞。 由于ThinkPHP5框架对控制器名没有进⾏⾜够的安全检测,导致在没有开

    2024年02月04日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包