精华内容
下载资源
问答
  • laravel workerman

    千次阅读 2018-05-23 13:04:04
    由于项目需要,要在laravel上面使用workerman,在网上查了好多资料,总结下,做下笔记,以便以后需要一、安装 workerman在项目根目录执行composer require workerman/workerman 二、创建自定义 artisan 命令来启动 ...
    由于项目需要,要在laravel上面使用workerman,在网上查了好多资料,总结下,做下笔记,以便以后需要

    一、安装 workerman

    在项目根目录执行

    composer require workerman/workerman
    
    二、创建自定义 artisan 命令来启动 workerman 服务

    由于 laravel 不能直接在根目录下执行 php 命令,所以需要创建 artisan  命令用于后面 workerman 服务的开启。

    1,生成 WorkermanCommand 文件

    php artisan make:command WorkermanCommand
    

    执行以上命令行会在 app/Console/Commands/ 目录下生成 WorkermanCommand.php 文件。

    <?php
        namespace App\Console\Commands;
        use Workerman\Worker;
        use Illuminate\Console\Command;
        class WorkermanCommand extends Command {
            private $server;
            // -d 是否以debug方式运行
            protected $signature = 'workerman {action} {-d?}';
            protected $description = 'Start a Workerman server.';
            public function __construct() {
                parent::__construct();
            }
    
            /** * Execute the console command. * * @return mixed */
            public function handle() {
                global $argv;
                $arg = $this->argument('action');
                $argv[1] = $argv[2];
                $argv[2] = isset($argv[3]) ? "-{$argv[3]}" : '';
    
                switch ($arg) {
                    case 'start':
                        $this->start();
                        break;
                    case 'stop':
                        $this->stop();
                        break;
                    case 'restart':
                        $this->restart();
                        break;
                    case 'reload':
                        $this->reload();
                        break;
                }
            }
            private function start() {
                // 创建一个Worker监听20002端口,不使用任何应用层协议
                $this->server = new Worker("tcp://0.0.0.0:8383");
                // 启动4个进程对外提供服务
                $this->server->count = 4;
                $handler = \App::make('handlers\WorkermanHandler');
                 // 连接时回调
                $this->server->onConnect = [$handler, 'onConnect'];
                 // 收到客户端信息时回调
                $this->server->onMessage = [$handler, 'onMessage'];
                 // 进程启动后的回调
                $this->server->onWorkerStart = [$handler, 'onWorkerStart'];
                 // 断开时触发的回调
                $this->server->onClose = [$handler, 'onClose'];
                 // 运行worker
                Worker::runAll();
            }
    
            private function stop() {
                $worker = new Worker('tcp://0.0.0.0:8383');
                // 设置此实例收到reload信号后是否reload重启
                $worker->reloadable = false;
                $worker->onWorkerStop = function($worker)
                {
                    echo "Worker reload...\n";
                };
                // 运行worker
                Worker::runAll();
            }
            private function restart() {
                $worker = new Worker('tcp://0.0.0.0:8383');
                // 设置此实例收到reload信号后是否reload重启
                $worker->reloadable = true;
                $worker->onWorkerStart = function($worker)
                {
                    echo "Worker restart...\n";
                };
                // 运行worker
                Worker::runAll();
            }
            private function reload() {
                $worker = new Worker('tcp://0.0.0.0:8383');
                // 设置此实例收到reload信号后是否reload重启
                $worker->reloadable = false;
                $worker->onWorkerStart = function($worker)
                {
                    echo "Worker reload...\n";
                };
                // 运行worker
                Worker::runAll();
            }
        }
    
    

    这里使用了 PHP 类方法的回调。(PHP几种回调写法
    这里我们创建了一个自定义命令 workerman [action]   [-d] ,通过此命令即可开启 workerman 服务。
    在这个自定义命令还引用了其他的类文件,如:

    $handler = \App::make('handlers\WorkermanHandler');
    

    所以,需要创建一个 WorkermanHandler.php 的文件来处理对应的操作。


    还需要在app/Console/Commands/Kernel.php 中增加

    protected $commands = [
        //
        \App\Console\Commands\WorkermanCommand::class
    
    ];

    2,创建 WorkermanHandler.php
    创建文件 app/handlers/WorkermanHandler.php

    <?php
        namespace handlers;
        use Workerman\Lib\Timer;
    
        // 心跳间隔10    define('HEARTBEAT_TIME',50);
    
        class WorkermanHandler {
            // 处理客户端连接
            public function onConnect($connection) {
                echo "链接成功";
            }
    
            // 处理客户端消息
            public function onMessage($connection, $data) {
                   //当上来数据获取最后上传数据的时间
                 $connection->lastMessageTime = time();
    
                // 向客户端发送hello $data
               $connection->send('Hello, your send message is: ' . $data);
            }
    
            // 处理客户端断开
            public function onClose($connection) {
                echo "connection closed from ip {$connection->getRemoteIp()}\n";
            }
    
            public function onWorkerStart($worker) {
                Timer::add(1, function () use ($worker) {
                    $time_now = time();
                    foreach ($worker->connections as $connection) {
                        // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
                        if (empty($connection->lastMessageTime)) {
                            $connection->lastMessageTime = $time_now;
                            continue;
                        }
                        // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
                        if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                            echo "Client ip {$connection->getRemoteIp()} timeout!!!\n"; $connection->close();
                        }
                    }
                });
            }
        }
    

    3,修改 composer.json 文件,让 app/handles 文件夹下的类文件自动加载。

    "autoload": {
        "classmap": [
            ...
            "app/handles"
        ],
        ...
    },
    

    至此。workman的命令定义已经完成。

    使用:
    php artisan workerman start d
    

    如果看到以下内容,说明 workerman 服务启动正常:

    Workerman[artisan] start in DEBUG mode
    ----------------------- WORKERMAN -----------------------------
    Workerman version:3.5.4          PHP version:7.1.4
    ------------------------ WORKERS -------------------------------
    user          worker        listen                   processes status
    root          none          tcp://0.0.0.0:8383   1         [OK] 
    ----------------------------------------------------------------
    Start success.
    展开全文
  • 一、安装workerman composer require ...在 laravel 的 app\Console\Commands 目录下生产了一个 WorkermanTimerCommand.php 文件 三、编写workerman控制台命令 <?php namespace App\Console\Commands;

    一、安装workerman

    composer require workerman/workerman

    二、编写artisan控制台命令

    php artisan make:command WorkermanTimerCommand

    在 laravel 的 app\Console\Commands 目录下生产了一个 WorkermanTimerCommand.php 文件

    三、编写workerman控制台命令

    <?php
    
    namespace App\Console\Commands;
    
    use App\Listens\WorkermanTimers;
    use Illuminate\Console\Command;
    use Workerman\Worker;
    
    class WorkermanTimerCommand extends Command
    {
        /**
         * 控制台命令的名称和参数.
         *
         * @var string
         */
        protected $signature = 'workerman {action} {--d}';
    
        /**
         * 控制台命令描述.
         *
         * @var string
         */
        protected $description = 'workerman的多进程定时任务';
    
        /**
         * Create a new command instance.
         *
         * @return void
         */
        public function __construct()
        {
            parent::__construct();
        }
    
        /**
         * Execute the console command.
         *
         * @return mixed
         */
        public function handle()
        {
            global $argv;
            $action = $this->argument('action');
            $argv[0] = 'wk';
            $argv[1] = $action;
            $argv[2] = $this->option('d') ? '-d' : '';
            $this->startServer();
        }
    
        /**
         * 启动workerman服务
         */
        public function startServer()
        {
            $worker = new Worker();
            // 服务名称.
            $worker->name = 'laravel timer';
            // 启动多少个进程数量,这里大家灵活配置,可以参考workerman的文档.
            $worker->count = 10;
            // 当workerman的进程启动时的回调方法.
            $worker->onWorkerStart = [WorkermanTimers::class, 'onWorkerStart'];
            // 当workerman的进程关闭时的回调方法.
            $worker->onClose = [WorkermanTimers::class, 'onClose'];
            Worker::runAll();
        }
    }

    四、编写定时器任务分发类WorkermanTimers

    在 app 目录下新建一个 Listens 目录,并创建 WorkermanTimers 类

    <?php
    /**
     * Created by PhpStorm.
     * User: Administrator
     * Date: 2020/12/21
     * Time: 19:08
     */
    
    namespace App\Listens;
    
    use Workerman\Lib\Timer;
    
    class WorkermanTimers
    {
        /**
         * 服务进程启动时
         * @param $businessWorker
         */
        public static function onWorkerStart($businessWorker)
        {
            // 拿到当前进程的id编号.
            $workid = $businessWorker->id;
            // 获取所有定时器任务配置.
            $timedTask = config('timers');
    
            if (is_array($timedTask)) {
                // 循环检测任务绑定.
                foreach ($timedTask as $key => $value) {
                    // 绑定任务进程.
                    if ($value['worker_id'] == $workid) {
                        Timer::add($value['time'], $value['func']);
                    }
                }
            }
    
        }
    
        /**
         * 服务进程结束时
         * @param $client_id
         */
        public static function onClose($client_id)
        {
        }
    
    }

     

    五、在 config/ 目录下新增一个 timers.php

    <?php
    
    return [
        // 定时任务名称.
        'clear_order' => [
            'worker_id' => 1, // 需要绑定的进程id.
            'time' => 5, // 时间间隔 秒为单位.
            'func' => 'Facades\App\Services\TestService::clear_order', // 定时执行的方法.
        ],
    ];


    timers.php 返回的是一个多维数据结构的配置,
    数组一级元素代表这个定时任务的名称(为了区分和理解),
    数组二级元素 worker_id 代表我们需要绑定到哪个进程
    数组二级元素 time 表示时间间隔,多少秒执行一次
    数组二级元素 func 代表要执行哪个方法

    在结合上面的 WorkermanTimers 类去看,就可以理解为:

    任务:clear_order绑定在进程编号为 1 的 worker 上面,每 5 秒就会执行一次 \App\Services\TestService 类里面的 clear_order方法

    在 laravel 里面,命名空间前面加上 Facades\ 就可以静态调用该类的方法,这部分的概念大家可以去看看 laravel 文档

    六、编写定时任务类
    我们在 app 目录下新建一个 Services 文件夹,并且新增一个 TestService 类

    TestService 类具体代码:

    <?php
    
    namespace App\Services;
    
    class TestService
    {
    
        public function testSay()
        {
            var_dump("Hello Laravel and Workerman");
        }
    
    }


    七、测试
    输入命令 php artison workerman start 启动 workerman

    看看有没有任务执行:

    命令:
    启动:

    php artisan workerman start


    启动常驻内存:

    php artisan workerman start --d


    其他命令:

    php artisan workerman reload //重新加载配置
    php artisan workerman reload //重启workerman
    php artisan workerman stop //停止workerman

    ————————————————
    原文作者:assimon
    转自链接:https://learnku.com/articles/42686
    版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请保留以上作者信息和原文链接。

     

     

     

    展开全文
  • 聊天功能是很常见的一种功能,Workerman是一款开源高性能异步PHP socket即时通讯框架。这篇文章主要介绍了workerman结合laravel开发在线聊天应用,感兴趣的小伙伴们可以参考一下
  • composer require workerman/gateway-worker composer require workerman/gatewayclient 创建 Workerman 启动文件app/Console/Commands/WorkermanCommand 命令:php artisan make:command WorkermanCommand <?php...

    安装

    composer require workerman/gateway-worker
    composer require workerman/gatewayclient

    创建 Workerman 启动文件app/Console/Commands/WorkermanCommand

    命令:php artisan make:command WorkermanCommand

    <?php
    
    namespace App\Console\Commands;
    
    use GatewayWorker\BusinessWorker;
    use GatewayWorker\Gateway;
    use GatewayWorker\Register;
    use Illuminate\Console\Command;
    use Workerman\Worker;
    
    class WorkermanCommand extends Command
    {
    
        protected $signature = 'workman {action} {--d}';
    
        protected $description = 'Start a Workerman server.';
    
        public function handle()
        {
            global $argv;
            $action = $this->argument('action');
    
            $argv[0] = 'wk';
            $argv[1] = $action;
            $argv[2] = $this->option('d') ? '-d' : '';
    
            $this->start();
        }
    
        private function start()
        {
            $this->startGateWay();
            $this->startBusinessWorker();
            $this->startRegister();
            Worker::runAll();
        }
    
        private function startBusinessWorker()
        {
            $worker                  = new BusinessWorker();
            $worker->name            = 'BusinessWorker';
            $worker->count           = 1;
            $worker->registerAddress = '127.0.0.1:1236';
            $worker->eventHandler    = \App\Workerman\Events::class;
        }
    
        private function startGateWay()
        {
            $gateway = new Gateway("websocket://0.0.0.0:2346");
            $gateway->name                 = 'Gateway';
            $gateway->count                = 1;
             $gateway->startPort            = 2300;
            $gateway->pingInterval         = 30;
            $gateway->pingNotResponseLimit = 0;
            $gateway->registerAddress      = '127.0.0.1:1236';
        }
    
        private function startRegister()
        {
            new Register('text://0.0.0.0:1236');
        }
    }
    
    

    创建事件监听文件app/Workerman/Events.php

    <?php
    namespace App\Workerman;
    use GatewayClient\Gateway;
    use Workerman\Lib\Timer;
    
    class Events
    {
        public static function onWorkerStart($businessWorker)
        {
        }
    
        public static function onConnect($client_id)
        {
            Gateway::sendToClient($client_id, json_encode(array(
                'type' => 'init',
                'client_id' => $client_id
            )));
    		//定时检测mac地址
            Timer::add(1800, function () use ($client_id) {
                $data = array('type' => 'mac');
                Gateway::sendToClient($client_id, json_encode($data));
            });
    
        }
    
        public static function onWebSocketConnect($client_id, $data)
        {
        }
    
        public static function onMessage($client_id, $message)
        {
        }
    
        public static function onClose($client_id)
        {
        }
    }
    
    

    启动 Workerman 服务端

    php artisan workman start --d

    后台使用

    <?php
    
    namespace app\Http\Controllers;
    
    use app\Models\User;
    use GatewayClient\Gateway;
    use Illuminate\Http\JsonResponse;
    use Illuminate\Http\Request;
    use Illuminate\Routing\Controller;
    use Illuminate\Support\Facades\Cache;
    
    class WorkermanController extends Controller
    {
        public function __construct()
        {
            Gateway::$registerAddress = '127.0.0.1:1236';
        }
    
        /**
         * websocket连接的client_id绑定用户的id
         * @param Request $request
         * @return JsonResponse
         */
        public function bind(Request $request): JsonResponse
        {
            try {
                $uid = auth()->id();
                $roles = Cache::get('user_role_' . $uid);
                Gateway::bindUid($request->get('client_id'), $uid);
                foreach ($roles as $role) {
                    Gateway::joinGroup($request->get('client_id'), 'role' . $role);
                    $menus = Cache::get('role_menu_' . $role);
                    foreach ($menus as $menu) {
                        Gateway::joinGroup($request->get('client_id'), 'menu' . $menu->id);
                    }
                }
                $data = array('msg' => '绑定成功');
                return res(compact('data'));
            } catch (\Exception $e) {
                throw new \Exception('绑定失败');
            }
        }
    
        /**
         * 根据用户更新权限
         * @param $userId
         */
        public function update_menus($userId)
        {
            $data = [];
            $permissions = User::menus($userId);
            $user = new User();
            $data['menus'] = recursion($permissions['menus'], 'id', 'parent_id', 'children', 0, false);
            $data['permissions'] = $permissions['webPermissions'];
            $user->update_token($userId, $permissions['permissions']);
            Gateway::sendToUid($userId, json_encode(array('type' => 'menus', 'data' => $data)));
        }
    
        public function update_menu_user($userId)
        {
            $userIds = Gateway::getAllUidList();
            if (in_array($userId, $userIds)) {
                $this->update_menus($userId);
            }
        }
    
        /**
         * 如果修改了角色数据,则用户更新权限
         * @param $roleId
         */
        public function update_menu_role($roleId)
        {
            $userIds = Gateway::getUidListByGroup('role' . $roleId);
            foreach ($userIds as $userId) {
                $this->update_menus($userId);
            }
        }
    
        /**
         * 如果修改了菜单数据,则用户更新权限
         * @param $menuId
         */
        public function update_menu_menu($menuId)
        {
            $userIds = Gateway::getUidListByGroup('menu' . $menuId);
            foreach ($userIds as $userId) {
                $this->update_menus($userId);
            }
        }
    
        /**
         * 更新登陆状态
         * @param $userId
         */
        public function update_login($userId)
        {
            $userIds = Gateway::getAllUidList();
            if (in_array($userId, $userIds)) {
                $data = User::query()->find($userId);
                $data->tokens()->where('tokenable_id', '=', $userId)->delete();
                Gateway::sendToUid($userId, json_encode(array('type' => 'logout')));
            }
        }
    
    }
    
    

    前端使用

    ws = new WebSocket('ws://192.168.10.106:2346');
    // 连接成功发送用户信息给后端
    ws.onopen = function () {
    };
    // 收到消息保存到vuex
    ws.onmessage = async function (e) {
        const type = JSON.parse(e.data).type
        const client_id = JSON.parse(e.data).client_id
        if (type === 'init') {
            //用户绑定client_id
        } else if (type === 'menus') {
            //更新菜单
        } else if (type === 'logout') {
            //退出
        } else if (type === 'mac') {
            //检测mac地址
        }
    }
    

    注意

    部署线上环境的时候,如果使用docker容易,需要将使用的端口放开。

    展开全文
  • laravel+workerman的demo

    千次阅读 2020-04-03 16:46:01
    https://github.com/lingdulvlv/laravel_workerman 安装laravel: composer create-project laravel/laravel=5.4.* --prefer-dist 安装workerman相关扩展: "workerman/gateway-worker": "^3.0", "workerman/...

    安装laravel:

    composer create-project laravel/laravel=5.4.* --prefer-dist

    安装workerman相关扩展:

    "workerman/gateway-worker": "^3.0",
    "workerman/gatewayclient": "^3.0",
    "workerman/workerman": "^3.5"

    做了简易的登录页面,数据库:

    路由web.php文件:

    Route::group(['namespace' => 'Home'], function () {
    	Route::get("login","LoginController@login");//登录
    	Route::get("dologin","LoginController@dologin");//登录处理
    	Route::get("company","ChatController@company");//公司列表
    	Route::get("chat/{id}","ChatController@chat");//公司聊天室
    });

    登录信息处理:LoginController.php中:

    <?php
    
    namespace App\Http\Controllers\Home;
    
    use Illuminate\Http\Request;
    use App\Http\Controllers\Controller;
    
    class LoginController extends Controller
    {
        public function login(Request $request)
        {
            return view('home.login');
        }
    
    
        public function dologin(Request $request)
        {
            $input = $request->all();
            $res = \DB::table('user')->where(['name'=>$input['name'], 'passwd'=>$input['passwd']])->first();
            if($res){
                $request->session()->put('loginuser', $res);
                $request->session()->save();
                return redirect('/company');
            }else{
                return redirect('/login');
            }
        }
    }

    对应登录的前端页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>登录</title>
    </head>
    <style>
    </style>
    <body>		
    	<form action="{{url('/dologin')}}">
    		<div style="width:200px; height:auto; margin:10% auto;">
    			<div>账号:<input type="text" value="唉吆喂" name="name" /></div>
    			<div>密码:<input type="text" value="123456" name="passwd" /></div>
    			<input type="submit" value="登录" style="margin:10px auto; display: block;" />
    		</div>
    	</form>
    </body>
    </html>
    <script type="text/javascript">
    </script>

    登录之后进入公司列表页

    ChatController.php:

    <?php
    
    namespace App\Http\Controllers\Home;
    
    use Illuminate\Http\Request;
    use App\Http\Controllers\Controller;
    
    class ChatController extends Controller
    {
        /**
        * 公司列表
        * @return [type] [description]
        */
        public function company()
        {
        	$res = \DB::table('company')->get();
        	return view('home.company',compact('res'));
        }
    
        /**
         * 公司聊天室
         * @param  Request $request    [description]
         * @param  [type]  $company_id [description]
         * @return [type]              [description]
         */
        public function chat(Request $request, $company_id)
        {
        	if($request->session()->has('loginuser')){
                $user = $request->session()->get("loginuser");
                $company = \DB::table('company')->where('company_id',$company_id)->first();
        		$company_all = \DB::table('company')->get();
                $user_all = \DB::table('user')->get();
                return view('home.chat',compact('user','company','company_all'));
            }else{
            	return redirect('/login');
            }
        }
    }
    

    公司列表前端页面:

    <html><head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>房间列表</title>
        <style type="text/css">
        .center{ width:800px; height:100%; background:#F5FAFF; margin:0 auto;}
        .room{ width:200px; height:100px; border:1px solid red; text-align:center; line-height:100px; float:left; margin:5px; }
        a{ color:green; }
        </style>
    </head>
    <body>
        <div class="center">
            @foreach($res as $key => $val)
            <a href="/chat/{{$val->company_id}}" target="_blank">
                <div class="room">
                    {{$val->company_name}}
                </div>
            </a>
            @endforeach
        </div>
    </body>
    </html>
    

    ====================核心代码=================

    聊天页面直接用的workerman聊天室的demo:https://www.workerman.net/workerman-chat

    <html><head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>{{$company->company_name}}PHP聊天室</title>
        <link href="{{asset('chat/css/bootstrap.min.css')}}" rel="stylesheet">
        <link href="{{asset('chat/css/jquery-sinaEmotion-2.1.0.min.css')}}" rel="stylesheet">
        <link href="{{asset('chat/css/style.css')}}" rel="stylesheet">
      
        <script type="text/javascript" src="{{asset('chat/js/swfobject.js')}}"></script>
        <script type="text/javascript" src="{{asset('chat/js/web_socket.js')}}"></script>
        <script type="text/javascript" src="{{asset('chat/js/jquery.min.js')}}"></script>
        <script type="text/javascript" src="{{asset('chat/js/jquery-sinaEmotion-2.1.0.min.js')}}"></script>
    
        <script type="text/javascript">
        if (typeof console == "undefined") {    this.console = { log: function (msg) {  } };}
        // 如果浏览器不支持websocket,会使用这个flash自动模拟websocket协议,此过程对开发者透明
        WEB_SOCKET_SWF_LOCATION = "{{asset('chat/swf/WebSocketMain.swf')}}";
        // 开启flash的websocket debug
        WEB_SOCKET_DEBUG = true;
        var ws, name, client_list={};
    
        // 连接服务端
        function connect() {
           // 创建websocket
            ws = new WebSocket("ws://"+document.domain+":2346");
           // 当socket连接打开时,输入用户名
            ws.onopen = onopen;
           // 当有消息时根据消息类型显示不同信息
            ws.onmessage = onmessage; 
            ws.onclose = function() {
                console.log("连接关闭,定时重连");
                connect();
            };
            ws.onerror = function() {
                console.log("出现错误");
            };
        }
    
        // 连接建立时发送登录信息
        function onopen()
        {
            if(!name)
            {
                show_prompt();
            }
            // 登录
            var login_data = '{"type":"login","client_name":"'+name.replace(/"/g, '\\"')+'","room_id":"'+'{{$company->company_id}}'+'"}';
            console.log("websocket握手成功,发送登录数据:"+login_data);
            ws.send(login_data);
        }
    
        // 服务端发来消息时
        function onmessage(e)
        {
            console.log(e.data);
            var data = JSON.parse(e.data);
            switch(data['type']){
                // 服务端ping客户端
                case 'ping':
                    ws.send('{"type":"pong"}');
                    break;;
                // 登录 更新用户列表
                case 'login':
                    //{"type":"login","client_id":xxx,"client_name":"xxx","client_list":"[...]","time":"xxx"}
                    say(data['client_id'], data['client_name'],  data['client_name']+' 加入了聊天室', data['time']);
                    if(data['client_list'])
                    {
                        client_list = data['client_list'];
                    }
                    else
                    {
                        client_list[data['client_id']] = data['client_name']; 
                    }
                    flush_client_list();
                    console.log(data['client_name']+"登录成功");
                    break;
                // 发言
                case 'say':
                    //{"type":"say","from_client_id":xxx,"to_client_id":"all/client_id","content":"xxx","time":"xxx"}
                    say(data['from_client_id'], data['from_client_name'], data['content'], data['time']);
                    break;
                // 用户退出 更新用户列表
                case 'logout':
                    //{"type":"logout","client_id":xxx,"time":"xxx"}
                    say(data['from_client_id'], data['from_client_name'], data['from_client_name']+' 退出了', data['time']);
                    delete client_list[data['from_client_id']];
                    flush_client_list();
            }
        }
    
        // 输入姓名
        function show_prompt(){
            // name = prompt('输入你的名字:', '');
            name = "{{$user->name}}"
            if(!name || name=='null'){  
                name = '游客';
            }
        }  
    
        // 提交对话
        function onSubmit() {
            var input = document.getElementById("textarea");
            var to_client_id = $("#client_list option:selected").attr("value");
            var to_client_name = $("#client_list option:selected").text();
            ws.send('{"type":"say","to_client_id":"'+to_client_id+'","to_client_name":"'+to_client_name+'","content":"'+input.value.replace(/"/g, '\\"').replace(/\n/g,'\\n').replace(/\r/g, '\\r')+'"}');
            input.value = "";
            input.focus();
        }
    
        // 刷新用户列表框
        function flush_client_list(){
            var userlist_window = $("#userlist");
            var client_list_slelect = $("#client_list");
            userlist_window.empty();
            client_list_slelect.empty();
            userlist_window.append('<h4>在线用户</h4><ul>');
            client_list_slelect.append('<option value="all" id="cli_all">所有人</option>');
            for(var p in client_list){
                userlist_window.append('<li id="'+p+'">'+client_list[p]+'</li>');
                client_list_slelect.append('<option value="'+p+'">'+client_list[p]+'</option>');
            }
            $("#client_list").val(select_client_id);
            userlist_window.append('</ul>');
        }
    
        // 发言
        function say(from_client_id, from_client_name, content, time){
            //解析新浪微博图片
            content = content.replace(/(http|https):\/\/[\w]+.sinaimg.cn[\S]+(jpg|png|gif)/gi, function(img){
                return "<a target='_blank' href='"+img+"'>"+"<img src='"+img+"'>"+"</a>";}
            );
    
            //解析url
            content = content.replace(/(http|https):\/\/[\S]+/gi, function(url){
                if(url.indexOf(".sinaimg.cn/") < 0)
                    return "<a target='_blank' href='"+url+"'>"+url+"</a>";
                else
                    return url;
            }
            );
    
            $("#dialog").append('<div class="speech_item"><img src="http://lorempixel.com/38/38/?'+from_client_id+'" class="user_icon" /> '+from_client_name+' <br> '+time+'<div style="clear:both;"></div><p class="triangle-isosceles top">'+content+'</p> </div>').parseEmotion();
        }
    
        $(function(){
            select_client_id = 'all';
            $("#client_list").change(function(){
                 select_client_id = $("#client_list option:selected").attr("value");
            });
            $('.face').click(function(event){
                $(this).sinaEmotion();
                event.stopPropagation();
            });
        });
        </script>
    </head>
    <body onload="connect();">
        <div class="container">
            <div class="row clearfix">
                <div class="col-md-1 column">
                </div>
                <div class="col-md-6 column">
                    <div class="thumbnail">
                        <div class="caption" id="dialog"></div>
                    </div>
                    <form onsubmit="onSubmit(); return false;">
                        <select style="margin-bottom:8px" id="client_list">
                            <option value="all">所有人</option>
                        </select>
                        <textarea class="textarea thumbnail" id="textarea"></textarea>
                        <div class="say-btn">
                            <input type="button" class="btn btn-default face pull-left" value="表情" />
                            <input type="submit" class="btn btn-default" value="发表" />
                        </div>
                    </form>
                    <div>
                        &nbsp;&nbsp;&nbsp;&nbsp;<b>房间列表:</b>(当前在&nbsp;房间{{$company->company_id}})<br>
                        @foreach($company_all as $key => $val)
                        &nbsp;&nbsp;&nbsp;&nbsp;<a href="/chat/{{$val->company_id}}">房间{{$val->company_id}}</a>
                        @endforeach
                        <br><br>
                    </div>
                </div>
                <div class="col-md-3 column">
                    <div class="thumbnail">
                        <div class="caption" id="userlist"></div>
                    </div>
                </div>
            </div>
        </div>
        <script type="text/javascript">
            // 动态自适应屏幕
            document.write('<meta name="viewport" content="width=device-width,initial-scale=1">');
            $("textarea").on("keydown", function(e) {
                // 按enter键自动提交
                if(e.keyCode === 13 && !e.ctrlKey) {
                    e.preventDefault();
                    $('form').submit();
                    return false;
                }
    
                // 按ctrl+enter组合键换行
                if(e.keyCode === 13 && e.ctrlKey) {
                    $(this).val(function(i,val){
                        return val + "\n";
                    });
                }
            });
        </script>
    </body>
    </html>
    

    创建workerman文件:

    php artisan make:command WorkermanCommand

    WorkermanCommand.php中:

    <?php
    
    namespace App\Console\Commands;
    
    use Illuminate\Console\Command;
    use GatewayWorker\BusinessWorker;
    use GatewayWorker\Gateway;
    use GatewayWorker\Register;
    use Workerman\Worker;
    
    class WorkermanCommand extends Command
    {
        /**
         * The name and signature of the console command.
         *
         * @var string
         */
        protected $signature = 'workerman {action} {--d}';
    
        /**
         * The console command description.
         *
         * @var string
         */
        protected $description = 'workerman';
    
        /**
         * Create a new command instance.
         *
         * @return void
         */
        public function __construct()
        {
            parent::__construct();
        }
    
        /**
         * Execute the console command.
         *
         * @return mixed
         */
        public function handle()
        {
            global $argv;
            $action = $this->argument('action');
    
            $argv[0] = 'wk';
            $argv[1] = $action;
            $argv[2] = $this->option('d') ? '-d' : '';
    
            $this->start();
        }
    
    
        private function start()
        {
            $this->startGateWay();
            $this->startBusinessWorker();
            $this->startRegister();
            Worker::runAll();
        }
    
        private function startBusinessWorker()
        {
            $worker                  = new BusinessWorker();
            $worker->name            = 'BusinessWorker';
            $worker->count           = 1;
            $worker->registerAddress = '127.0.0.1:1236';
            $worker->eventHandler    = \App\Events\Workerman::class;
        }
    
        private function startGateWay()
        {
            $gateway = new Gateway("websocket://0.0.0.0:2346");
            $gateway->name                 = 'Gateway';
            $gateway->count                = 1;
            $gateway->lanIp                = '127.0.0.1';
            $gateway->startPort            = 2300;
            $gateway->pingInterval         = 30;
            $gateway->pingNotResponseLimit = 0;
            $gateway->pingData             = '{"type":"@heart@"}';
            $gateway->registerAddress      = '127.0.0.1:1236';
        }
    
        private function startRegister()
        {
            new Register('text://0.0.0.0:1236');
        }
    }
    

    记得把命令文件添加进Kernel.php的$commands中:

    protected $commands = [
        \App\Console\Commands\WorkermanCommand::class
    ];

    创建事件监听文件:

    php artisan make:event Workerman

    Workerman.php文件中放wokerman-chat的demo中的Applications/Chat/Events.php的内容

    <?php
    
    namespace App\Events;
    
    use GatewayWorker\Lib\Gateway;
    
    class Workerman
    {
        /**
        * 有消息时
        * @param int $client_id
        * @param mixed $message
        */
        public static function onMessage($client_id, $message)
        {
            // debug
            echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id session:".json_encode($_SESSION)." onMessage:".$message."\n";
            
            // 客户端传递的是json数据
            $message_data = json_decode($message, true);
            if(!$message_data)
            {
                return ;
            }
            
            // 根据类型执行不同的业务
            switch($message_data['type'])
            {
                // 客户端回应服务端的心跳
                case 'pong':
                    return;
                // 客户端登录 message格式: {type:login, name:xx, room_id:1} ,添加到客户端,广播给所有客户端xx进入聊天室
                case 'login':
                    // 判断是否有房间号
                    if(!isset($message_data['room_id']))
                    {
                        throw new \Exception("\$message_data['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']} \$message:$message");
                    }
                    
                    // 把房间号昵称放到session中
                    $room_id = $message_data['room_id'];
                    $client_name = htmlspecialchars($message_data['client_name']);
                    $_SESSION['room_id'] = $room_id;
                    $_SESSION['client_name'] = $client_name;
                  
                    // 获取房间内所有用户列表 
                    $clients_list = Gateway::getClientSessionsByGroup($room_id);
                    foreach($clients_list as $tmp_client_id=>$item)
                    {
                        $clients_list[$tmp_client_id] = $item['client_name'];
                    }
                    $clients_list[$client_id] = $client_name;
                    
                    // 转播给当前房间的所有客户端,xx进入聊天室 message {type:login, client_id:xx, name:xx} 
                    $new_message = array('type'=>$message_data['type'], 'client_id'=>$client_id, 'client_name'=>htmlspecialchars($client_name), 'time'=>date('Y-m-d H:i:s'));
                    Gateway::sendToGroup($room_id, json_encode($new_message));
                    Gateway::joinGroup($client_id, $room_id);
                   
                    // 给当前用户发送用户列表 
                    $new_message['client_list'] = $clients_list;
                    Gateway::sendToCurrentClient(json_encode($new_message));
                    return;
                    
                // 客户端发言 message: {type:say, to_client_id:xx, content:xx}
                case 'say':
                    // 非法请求
                    if(!isset($_SESSION['room_id']))
                    {
                        throw new \Exception("\$_SESSION['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
                    }
                    $room_id = $_SESSION['room_id'];
                    $client_name = $_SESSION['client_name'];
                    
                    // 私聊
                    if($message_data['to_client_id'] != 'all')
                    {
                        $new_message = array(
                            'type'=>'say',
                            'from_client_id'=>$client_id, 
                            'from_client_name' =>$client_name,
                            'to_client_id'=>$message_data['to_client_id'],
                            'content'=>"<b>对你说: </b>".nl2br(htmlspecialchars($message_data['content'])),
                            'time'=>date('Y-m-d H:i:s'),
                        );
                        Gateway::sendToClient($message_data['to_client_id'], json_encode($new_message));
                        $new_message['content'] = "<b>你对".htmlspecialchars($message_data['to_client_name'])."说: </b>".nl2br(htmlspecialchars($message_data['content']));
                        return Gateway::sendToCurrentClient(json_encode($new_message));
                    }
                    
                    $new_message = array(
                        'type'=>'say', 
                        'from_client_id'=>$client_id,
                        'from_client_name' =>$client_name,
                        'to_client_id'=>'all',
                        'content'=>nl2br(htmlspecialchars($message_data['content'])),
                        'time'=>date('Y-m-d H:i:s'),
                    );
                    return Gateway::sendToGroup($room_id ,json_encode($new_message));
            }
        }
       
       /**
        * 当客户端断开连接时
        * @param integer $client_id 客户端id
        */
        public static function onClose($client_id)
        {
            // debug
            echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id onClose:''\n";
           
            // 从房间的客户端列表中删除
            if(isset($_SESSION['room_id']))
            {
                $room_id = $_SESSION['room_id'];
                $new_message = array('type'=>'logout', 'from_client_id'=>$client_id, 'from_client_name'=>$_SESSION['client_name'], 'time'=>date('Y-m-d H:i:s'));
                Gateway::sendToGroup($room_id, json_encode($new_message));
            }
        }
    }
    

    运行workerman

    php artisan workerman start

    进入聊天室:

     

    项目地址:https://github.com/lingdulvlv/laravel_workerman

     

     

     

    展开全文
  • 命令:composer require workerman/gateway-worker 2. 创建 Workerman 启动文件 命令: php artisan make:command WorkermanCommand 生成的文件路径: Console\Commands\WorkermanCommand.php 3 WorkermanCommand....
  • laravel使用workerman 用户交互、服务器交互 使用workeman实现浏览器相互通信、服务器浏览器交互 ## 一. 安装workerman ``` composer require workerman/workerman ``` ## 二. 生成命令文件 ``` ...
  • laravel+workerman(ws)

    2020-09-30 14:00:58
    <?... namespace App\Console\Commands; use GatewayWorker\BusinessWorker; use GatewayWorker\Gateway;...use Workerman\Worker; class WorkermanWebs extends Command { protected $signature = 'wk:w
  • laravel 使用workerman加速应用

    千次阅读 2019-04-08 18:00:04
    公司项目使用的是laravel框架,开发完后压测一直不过,期间开启过opcache扩展加速(不属于本篇内容,不在此赘述),后决定采用workerman或swoole加速laravel应用,本篇以workerman为例。 首先大家应该知道laravel...
  • 官方建议分离 workerman和mvc框架的结合,我去,这不是有点脑缺氧吗? 大量的业务逻辑,去独立增加方法和类库在写一次,实际业务中是不现实和不实际的 gateway增加一些这方面的工作,但是我看了源码之后,就发现还是...
  • 2.创建laravel自定义命令 php artisan make:command Workerman 注:执行这段命令后会在\app\Console\Commands文件夹下生成Workerman.php文件 3.命令文件代码Workerman.php: <?php namespace App\Conso...
  • 4-1 你也可以指定某张表生成迁移文件 php artisan migrate:generate table1,table2,table3 4-2 也可以反向忽略某些表 php artisan migrate:generate --ignore="table3,table4,table5" ⑤laravel配置workerman实现wss...
  • workerman 实时通讯

    2019-08-31 15:35:56
    workerman 实现了即时通讯。 基于长连接,可以做即时通讯,直播,等等功能,也希望可以举一反三,实现其他功能。 具体看代码,github仓库 https://github.com/lizhilicctv/chat ,码云仓库,...
  • 测试工具...2018年8月6日17:28:24 <?... namespace App\Console\Commands; use Illuminate\Console\Command;...use Workerman\Worker; use App\Work\ChatroomWork; class Chatroo...
  • laravel 中使用workerman

    2020-07-01 16:34:17
    守护进程方式启动: protected $signature = ‘workerman {action}{–d}’; $arg = $this->argument(‘action’); $argv[1] = $arg; $argv[2] = $this->option(‘d’) ? ‘-d’ : ‘’;//该参数是以d
  • [在 Laravel 中使用 Workerman 进行 socket 通讯 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区]1.安装 Workerman由于要使用客户端点对点通讯,选择了 workerman/gateway-worker 的扩展包,它已经引入...
  • 使用composer安装, 所以先要确保安装了composer工具 1. 为了安装快, 安装一个composer扩展hirak/prestissimo, 可以多线程下载 composer global ... 安装 gateway-worker composer require workerman/gateway-worker
  • laravel框架整合workerman

    千次阅读 2018-05-19 11:21:42
    配置 首先运行命令检测当前cli环境是否支持: curl -Ss http://www.workerman.net/check.php | php php -m //查看当前cli环境php模块 某些集成环境cli的配置文件... ...composer安装workerman cd your_path/larave...
  • 下载地址:https://itfun.tv/chapters/185/body 5、打开终端,进入Laravel项目,执行命令:composer require workerman/gatewayclient 6、进入后台的Customer控制器对应的方法中,写上监听地址,并通过sendToGroup...
  • 一、安装 workerman在项目根目录执行composer require workerman/workerman二、创建自定义 artisan 命令来启动 workerman 服务由于 laravel 不能直接在根目录下执行 php 命令,所以需要创建 artisan 命令用于后面 ...
  •  首先在laravel根目录下安装Workerman  命令:$ composer require workerman/gateway-worker 2.创建 Workerman 启动文件  创建一个 artisan 命令行工具来启动 Socket 服务端,在 app/Console/Commands 目录下...
  • gateway-worker 它已经引入了 workerman/workerman. composer require workerman/gateway-worker 如果找不到此包,建议更换composer源。阿里的源找不到,我重置到官方源可以安装。源连接 2. 创建 Workerman ...
  • 1、报告 already running 的原因是因为workerman要求不能重复启动已经在运行的同一个启动脚本,这是为了准确的stop 、restart等所需。在laravel中artisan脚本就相当于我们常见的 start.php 启动脚本,根据这个原理...
  • laravel + (workerman gateway-worker)

    千次阅读 2018-04-25 10:22:29
    "workerman/workerman": "^3.5" }, 2. 执行安装命令 composer install 或 composer update 安装成功继续下一步  二 集合到laravel框架 1.Events.php 处理消息发送接收逻辑 /** * This file is part of ...
  • git地址:https://gitee.com/hzbskak/laravel_worker 环境 PHP 7.4.19、Laravel Framework 5.8.38、mysql Ver 14.14 Distrib 5.7.33 下载laravel composer create-project --...https://www.workerman.net/downlo.
  • 将代码部署到linux下 报错Unknown command: workerman Usage: php yourfile <command> [mode] 根据下文,将Worker.php中所有argv参数加1 http...
  • 功能要求:数据有变化时,更新所有访问者的页面数据。针对每个登录用户,返回不同的用户数据 不同数据:每个用户不同的竞买号,当前登录用户是否交了保证金,是否...已有laravel 配置Gateway Worker 去这个地址把dem

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 521
精华内容 208
关键字:

laravelworkerman