PHP实现Workerman实例 高性能PHP Socket即时通讯框架

简介: PHP实现Workerman实例 高性能PHP Socket即时通讯框架

安装

首先通过 composer 安装

composer require topthink/think-worker

使用

SocketServer

在命令行启动服务端(需要2.0.5+版本)

php think worker:server

默认会在0.0.0.0:2345开启一个websocket服务。

如果需要自定义参数,可以在config/worker_server.php中进行配置,包括:

配置参数

描述

protocol

协议

host

监听地址

port

监听端口

socket

完整的socket地址

并且支持workerman所有的参数(包括全局静态参数)。

也支持使用闭包方式定义相关事件回调。

return [
  'socket'  =>  'http://127.0.0.1:8000',
  'name'    =>  'thinkphp',
  'count'   =>  4,
  'onMessage' =>  function($connection, $data) {
    $connection->send(json_encode($data));
  },
];

复制

也支持使用自定义类作为Worker服务入口文件类。例如,我们可以创建一个服务类(必须要继承 think\worker\Server),然后设置属性和添加回调方法

然后在worker_server.php中增加配置参数:

return [
  'worker_class'  =>  'app\http\Workerman',
];

app\http\Workerman.php

<?php
namespace app\http;
use think\Log;
use think\worker\Server;
use Workerman\Lib\Timer;
class Worker extends Server
{
    // socket 端口
    protected $worker;
    protected $processes = 1; // 一个进程数
    protected $socket = '';
    protected $uidConnections = []; // 用户连接
    protected $heartbeat_time = 55; // 心跳间隔检测
    protected $send_heartbeat_time = 10; // 发送心跳间隔
    protected $time_countdown = 0; // 计算时间
    public function __construct()
    {
        $this->socket = 'http://0.0.0.0:2345';
        parent::__construct();
    }
    /**
     * 收到信息
     */
    public function onMessage($connection, $data)
    {
        $connection->lastMessageTime = time();
        $connection->send(json_encode($data));
    }
    /**
     * 当连接建立时触发的回调函数
     */
    public function onConnect($connection)
    {
    }
    /**
     * 当连接断开时触发的回调函数
     */
    public function onClose($connection)
    {
        // 删除
        if (isset($connection->uid) && isset($this->uidConnections[$connection->uid])) {
            //unset($this->uidConnections[$connection->uid][$connection->id]);
            unset($this->uidConnections[$connection->uid]);
        }
    }
    /**
     * 当客户端的连接上发生错误时触发
     */
    public function onError($connection, $code, $msg)
    {
        ////echo "error $code $msg\n";
    }
    /**
     * 发送给所有人
     */
    private function sendAll($data, $flg = false, $type = '')
    {
        $msg = json_encode([
            'event' => '#publish',
            'data' => $data,
            'type' => $type
        ]);
        $connection_check = [];
        // 发送给登录的用户
        // foreach ($this->uidConnections as $connection) {
        //     $end = current($connection);
        //     $end->send($msg);
        //     $connection_check[] = $end->id;
        // }
        // 发送给所有人
        foreach ($this->worker->connections as $connection) {
            if (in_array($connection->id, $connection_check)) {
                continue;
            }
            $connection->send($msg);
        }
    }
    /**
     * 发送给指定用户
     */
    private function sendMsg($uid, $data, $type)
    {
        $msg = json_encode([
            'type' => $type,  //待处理todo 多种type消息
            'data' => $data,
            'alert' => true,
        ]);
        $uid = intval($uid);
        // 判断是否有在线的连接
//        if (isset($this->uidConnections[$uid])) {
//            $end = $this->uidConnections[$uid];
//            $end->send($msg);
//        }
        // 判断是否有在线的连接
        if (isset($this->uidConnections[$uid]) && $this->uidConnections[$uid]) {
            //$end = end($this->uidConnections[$uid]);
            //$end->send($msg);
            foreach ($this->uidConnections[$uid] as $connection) {
                $connection->send($msg);
            }
        }
    }
    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
        //每秒执行
        Timer::add(1, function () use ($worker) {
            $this->time_countdown++;
            $time_now = time();
            foreach ($worker->connections as $connection) {
                $connection->send('time_countdown:' . $this->time_countdown);
                // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
                // 统一下发心跳
                if ($this->time_countdown % $this->send_heartbeat_time == 0) {
                    $connection->send(json_encode([
                        'type' => 'hello time',
                    ]));
                }
                if (empty($connection->lastMessageTime)) {
                    $connection->lastMessageTime = $time_now;
                    continue;
                }
                // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
                if ($time_now - $connection->lastMessageTime > $this->heartbeat_time) {
                    $connection->close();
                }
            }
        });
    }
}

关于上传文件

当按照默认的worker做http服务器时,并不能直接使用request()->file('image')来获得上传的文件,具体可以参考workerman的上传文件第6点.因此只能迂回的使用Filesystem.无论怎样,不影响其getMime()等方法的正确性.

// $file = request()->file('image');
$file_data  =  $_FILES[0]['file_data'];
//$tmp_file  = tempnam('','tm_');  这种写法最终保存时扩展名为.tmp
$tmp_file  = sys_get_temp_dir().'/'.uniqid().'.'.explode('/',$_FILES[0]['file_type'])[1];
file_put_contents($tmp_file,$file);
$file  =  new  File($tmp_file);
$savename  =  Filesystem::putFile('upload',$file);
echo  $savename;

自定义workerman指令

有时候我们希望使用think的命令行运行workerman,这里做一个介绍,

1:先新建一个指令,参考文档:自定义指令,比如新建命令:

php think make:command Hello hello

2:复制下面的代码到指令里,覆盖原始的configureexecute方法

protected function configure()
  {
    // 指令配置
    $this->setName('convert')
      ->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')
      ->addOption('mode', 'm', Option::VALUE_OPTIONAL, 'Run the workerman server in daemon mode.')
      ->setDescription('the workerman command');
  }
  protected function execute(Input $input, Output $output)
  {
    // 指令输出
    $output->writeln('convert start');
    $action = $input->getArgument('action');
    $mode = $input->getOption('mode');
    // 重新构造命令行参数,以便兼容workerman的命令
    global $argv;
    $argv = [];
    array_unshift($argv, 'think', $action);
    if ($mode == 'd') {
      $argv[] = '-d';
    } else if ($mode == 'g') {
      $argv[] = '-g';
    }
    // 在这里放心的实例化worker,
    // 就像参照workerman文档写一样,
    // 无非在workerman的文档里,代码是新建纯php文件,但在这里,写到了一个方法里.
    $worker_1 = new Worker();
    $worker_2 = new Worker();
    Worker::runAll();
  }

3:运行的时候,使用如下命令:

//临时运行
php think hello start
//后台运行
php think hello start --mode d


目录
相关文章
|
19天前
|
消息中间件 缓存 弹性计算
纯PHP+MySQL手搓高性能论坛系统!代码精简,拒绝臃肿
本内容分享了一套经实战验证的社交系统架构设计,支撑从1到100万用户的发展,并历经6次流量洪峰考验。架构涵盖客户端层(App、小程序、公众号)、接入层(API网关、负载均衡、CDN)、业务服务层(用户、内容、关系、消息等服务)、数据层(MySQL、Redis、MongoDB等)及运维监控层(日志、监控、告警)。核心设计包括数据库分库分表、多级缓存体系、消息队列削峰填谷、CQRS模式与热点数据动态缓存。同时提供应对流量洪峰的弹性伸缩方案及降级熔断机制,并通过Prometheus实现全链路监控。开源建议结构清晰,适合大型社交平台构建与优化。
109 11
|
6月前
|
SQL 安全 PHP
PHP 自发布以来一直在 Web 开发领域占据重要地位,PHP 8 更是带来了属性、刚性类型等新特性。
【10月更文挑战第1天】PHP 自问世以来,凭借其易用性和灵活性,在 Web 开发领域迅速崛起。从简单的网页脚本语言逐步演进为支持面向对象编程的现代语言,尤其自 PHP 5.3 引入命名空间后,代码组织和维护变得更加高效。PHP 7 的性能优化和 PHP 8 的新特性(如属性和刚性类型)进一步巩固了其地位。框架如 Laravel、Symfony、Yii2 和 CodeIgniter 等简化了开发流程,提高了效率和安全性。
106 2
|
7月前
|
设计模式 算法 数据库连接
PHP中的设计模式:提高代码的可维护性与扩展性本文旨在探讨PHP中常见的设计模式及其应用,帮助开发者编写出更加灵活、可维护和易于扩展的代码。通过深入浅出的解释和实例演示,我们将了解如何使用设计模式解决实际开发中的问题,并提升代码质量。
在软件开发过程中,设计模式是一套经过验证的解决方案模板,用于处理常见的软件设计问题。PHP作为流行的服务器端脚本语言,也有其特定的设计模式应用。本文将重点介绍几种PHP中常用的设计模式,包括单例模式、工厂模式和策略模式,并通过实际代码示例展示它们的具体用法。同时,我们还将讨论如何在实际项目中合理选择和应用这些设计模式,以提升代码的可维护性和扩展性。
135 4
|
3月前
|
SQL 缓存 PHP
PHP框架详解 - symfony框架
Symfony框架凭借其灵活性、高性能和强大的社区支持,成为PHP开发领域的重要工具。无论是初学者还是资深开发者,都可以通过Symfony快速构建高质量的Web应用程序。通过深入理解Symfony的核心组件和最佳实践,开发者可以充分发挥其优势,提升开发效率和代码质量。
84 24
|
5月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
108 5
|
5月前
|
PHP
PHP的pcntl多进程用法实例
PHP使用PCNTL系列的函数也能做到多进程处理一个事务。
58 12
|
5月前
|
SQL 安全 PHP
PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全
本文深入探讨了PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全。
178 4
|
5月前
|
API PHP 数据库
PHP中哪个框架最适合做API?
在数字化时代,API作为软件应用间通信的桥梁至关重要。本文探讨了PHP中适合API开发的主流框架,包括Laravel、Symfony、Lumen、Slim、Yii和Phalcon,分析了它们的特点和优势,帮助开发者选择合适的框架,提高开发效率、保证接口稳定性和安全性。
223 3
|
5月前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP是一种流行的服务器端脚本语言,自诞生以来在Web开发领域占据重要地位。从简单的网页脚本到支持面向对象编程的现代语言,PHP经历了多次重大更新。本文探讨PHP的现代演进历程,重点介绍其在Web开发中的应用及框架创新,如Laravel、Symfony等。这些框架不仅简化了开发流程,还提高了开发效率和安全性。
59 3
|
5月前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP 自发布以来一直在 Web 开发领域占据重要地位,历经多次重大更新,从简单的脚本语言进化为支持面向对象编程的现代语言。本文探讨 PHP 的演进历程,重点介绍其在 Web 开发中的应用及框架创新。自 PHP 5.3 引入命名空间后,PHP 迈向了面向对象编程时代;PHP 7 通过优化内核大幅提升性能;PHP 8 更是带来了属性、刚性类型等新特性。
71 3

热门文章

最新文章

下一篇
oss创建bucket