技术&日志

laravel-workerman简易聊天室

ENV

php-7.2 | Laravel-5.5 | workerman-3.5

安装workerman

在安装好laravel的目录中执行命令composer require workerman/workerman

laravel创建命令控制器

php artisan make:command Workerman

laravel与workerman整合

上面命令会创建文件app\Console\Commands\Workerman.php 将下面代码复制并替换掉原来代码.

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Workerman\Worker;
use Workerman\Autoloader;
class Workerman extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'Workerman {action}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {   
        global $argv;
        $arg = $this->argument('action');
        $argv [1] = $arg;

        global $text_worker;
        // 创建一个Worker监听9130端口,使用http协议通讯
        $text_worker = new Worker("websocket://0.0.0.0:8080");
/*        $http_worker->transport = 'http';*/
        // 启动4个进程对外提供服务
        $text_worker->count = 4;
        $handler = \App::make('Handler\WorkermanHandler');
        $text_worker->onConnect = array($handler,"handle_connection");
        $text_worker->onMessage = array($handler,"handle_message");
        $text_worker->onClose = array($handler,"handle_close");

        // 运行worker
        Worker::runAll();
    }

}

手动创建文件app\Handler\WorkermanHandler.php 将下面代码复制替换

<?php
namespace Handler;

use Illuminate\Console\Command;
use Workerman\Worker;

class WorkermanHandler
{

    protected $global_uid = 0;

    //当客户端连上来时分配uid,并保存链接,并通知所有客户端
    public function handle_connection($connection){
      global $text_worker, $global_uid;
      //为这个链接分配一个uid
      $connection->uid = ++$global_uid;
      foreach($text_worker->connections as $conn){
        $conn->send("user:[{$connection->uid}] online");
      }
    }

    //当客户端发送消息过来时,转发给所有人
    public function handle_message($connection,$data){
      global $text_worker;
      foreach($text_worker->connections as $conn){
        $conn->send("user:[{$connection->uid}] said:$data");
      }
    }

    //当客户端断开时,广播给所有客户端
    public function handle_close($connection){
      global $text_worker;
      foreach($text_worker->connections as $conn){
        $conn->send("user:[{$connection->uid}] logout");
      }
    }

}

打开composer.json文件增加一段"app/Handler"于classmap中下面是我的部分内容

...
    "autoload": {
        "classmap": [
            "database/seeds",
            "database/factories",
            "app/Handler" 
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },
...

执行命令: composer dump-autoload

H5 websokcet代码-(参考资料中的资料4)

启动服务

php artisan Workerman start

tip
app\Console\Commands\Workerman.php 里的代码 $arg = $this->argument('action'); $argv [1] = $arg; 如果这段代码不写那么就无法启动服务会报Usage: php yourfile.php {start|stop|restart|reload|status|connections} [-d]

原因: 参考接收位置错误. 代码位置: \vendor\workerman\workerman\Worker.php 673 684, 问题位置 673行中, $argv 这个全局变量取的key的位置错乱的.

参考资料

资料1-laravel使用Workerman搭建简易聊天室
资料2-Laravel — Laravel5.3 和 Workerman结合使用(异步)
资料3-HTML5 WebSocket
资料4-workerman-github