codemash/laravel-socket

此包已被废弃,不再维护。未建议替代包。

Laravel 5 的 Socket 实现

1.0.0 2016-09-04 15:13 UTC

This package is not auto-updated.

Last update: 2020-02-07 16:10:14 UTC


README

此包允许您在 Laravel 5 应用程序中轻松优雅地使用套接字。基于出色的 PHP 套接字库,Ratchet。阅读下面的说明以进行设置。

要求

Laravel 5.x。

安装

您可以使用 Composer 包管理器安装此包。您可以在项目根目录下运行以下命令进行安装

composer require codemash/laravel-socket

Codemash\Socket\SocketServiceProvider 提供者添加到 config/app.php 中的 providers 数组中

'providers' => [
    ...
    Codemash\Socket\SocketServiceProvider::class,
],

然后,将外观添加到您的 aliases 数组中。默认外观提供了一个易于使用的接口,用于将套接字文件集成到视图中。

'aliases' => [
    ...
    'Socket' => Codemash\Socket\Facades\Socket::class,
]

最后,需要发布配置和 JavaScript 文件,可以通过运行以下命令完成

php artisan vendor:publish --provider="Codemash\Socket\SocketServiceProvider"

发布的资产可以在 config/socket.php 中找到,默认 JavaScript 在 public/vendor/socket/socket.js 中。重要的是要知道,Socket::javascript() 外观函数将包含位于 window.appSocket 的默认套接字以及位于 vendor 文件夹中的 socket.js 源文件。这些都是起点,并提供了一种快速处理套接字的方法,但您始终可以自由编写自定义实现。

入门

让我们创建一个简单的应用程序,该应用程序将消息发送到所有其他连接的客户端。当套接字操作发生时,它将被包装在 Laravel 事件中并触发。这是我们捕捉这些事件并采取行动的绝佳方式。让我们在 app/Providers/EventServiceProvider.php 文件中注册我们的监听器,如下所示

<?php

namespace App\Providers;

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
   ...

    /**
    * The subscriber classes to register.
    *
    * @var array
    */
    protected $subscribe = [
        'App\Listeners\MessageEventListener'
    ];
}

并在以下路径创建监听器: app/Listeners/MessageEventListener.php。监听器提供了 3 个基本事件。在我们的例子中,我们将仅使用 onMessageReceived 事件。

<?php

namespace App\Listeners;

use Codemash\Socket\Events\MessageReceived;
use Codemash\Socket\Events\ClientConnected;
use Codemash\Socket\Events\ClientDisconnected;

class MessageEventListener {

    public function onMessageReceived(MessageReceived $event)
    {
        $message = $event->message;

        // If the incomming command is 'sendMessageToOthers', forward the message to the others.
        if ($message->command === 'sendMessageToOthers') {
            // To get the client sending this message, use the $event->from property.
            // To get a list of all connected clients, use the $event->clients pointer.
            $others = $event->allOtherClients();
            foreach ($others as $client) {
                // The $message->data property holds the actual message
                $client->send('newMessage', $message->data);
            }
        }
    }

    public function onConnected(ClientConnected $event)
    {
        // Not used in this example.
    }

    public function onDisconnected(ClientDisconnected $event)
    {
        // Not used in this example.
    }

    /**
     * Register the listeners for the subscriber.
     *
     * @param  Illuminate\Events\Dispatcher  $events
     */
    public function subscribe($events)
    {
        $events->listen(
            'Codemash\Socket\Events\ClientConnected',
            'App\Listeners\MessageEventListener@onConnected'
        );

        $events->listen(
            'Codemash\Socket\Events\MessageReceived',
            'App\Listeners\MessageEventListener@onMessageReceived'
        );

        $events->listen(
            'Codemash\Socket\Events\ClientDisconnected',
            'App\Listeners\MessageEventListener@onDisconnected'
        );

    }
}

上述应用程序执行的操作如下:连接的客户端发送一条消息,带有 sendMessageToOthers 命令,该命令基本上将消息转发到您的应用程序中所有其他连接的客户端。重要的是要注意,客户端与 User 模型不同。客户端仅是从某个人的浏览器到您的 Laravel 应用的连接,无论该用户是否已认证。存在从连接获取已连接认证模型的可能性,关于这一点稍后介绍。

现在轮到编写客户端代码了,幸运的是,Socket 外观可以立即处理。创建一个具有以下内容的 blade 模板

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <button onclick="sendMessage()">Send message</button>
        {!! Socket::javascript() !!}
        <script>
            var socket = window.appSocket;

            function sendMessage() {
                var text = window.prompt('Which message would you like to send?');
                socket.send('sendMessageToOthers', text);
            }

            socket.on('newMessage', function (newMessage) {
                alert('New message: ' + newMessage);
            });

            socket.connect(function () {
                // The socket is connected.
            });
        </script>
    </body>
</html>

最后,让我们运行套接字监听器。您可以在项目根目录下运行以下 artisan 命令来完成此操作

php artisan socket:listen

客户端连接

使用 Eloquent 模型

Laravel Socket在可用时会读取会话,并将User Eloquent模型映射到您的客户端。然后您可以使用以下代码检索Eloquent模型

foreach ($clients as $client) {
    if ($client->authed()) {
        $user = $client->getUser();
        // $user now holds the App\User model,
        // or the model set in the 'config.auth.providers.users.model' config variable.
    }
}

当您使用客户端列表,如$event->clients时,这是一个Laravel集合对象。filter、map等方法在此上运行非常好。

存储与客户端相关的数据

客户端对象实现了魔术方法,这意味着您可以在服务器运行的生命周期中设置任何类型的附加属性。如果您访问一个不存在的属性,它将触发一个异常。假设您想设置一个包含客户端连接时的时间戳的connected_at属性。我们将在事件监听器中的onConnected方法中添加此属性,如下所示

public function onConnected(ClientConnected $event)
{
    $event->client->connected_at = Carbon::now();
}

public function onMessageReceived(MessageReceived $event)
{
    if ($event->message->command === 'whenDidIConnect') {
        if (isset($event->from->connected_at)) {
            $event->from->send('iConnectedAt', $event->from->connected_at->toString());
        }
    }
}

生产环境

Ubuntu提供了方便的nohup工具,可以在后台运行进程。如果您想在Ubuntu上运行生产服务器上的socket,您可以使用nohup工具来运行socket监听器。

nohup php artisan socket:listen &

使用jobs命令时,您会看到socket正在运行。使用kill <pid>命令可以轻松地终止进程。进程ID列在作业列表中。

贡献

如果您遇到问题,发现错误,或有功能建议,请在Github上记录问题。如果您想自己尝试,可以fork这个包并提交一个pull request。任何改进都受欢迎。