WebSocketBundle-舍弃浪费资源的ajax轮询吧【原创】

2017-09-07 望水一鱼

WebSocketBundle 是一个基于react/socket实现Socket的一个第三方Bundle,GitHub地址 WebSocketBundle ,当然其主要功能是聊天功能,这里也是为了作为之前商城类项目中有类似前台用户下单后台需要弹窗提示类功能解决方案

安装篇

声明:此步骤基于symfony2.8进行

因为此Bundle基于react/socket故在composer.json中追加上”react/socket”: “^0.4.6″后执行composer update

#composer.json
"require": {
      ..//  
    "react/socket": "^0.4.6"
},

之后再进行正常安装

composer require gos/web-socket-bundle

注册Bundle

<?php
// app/AppKernel.php

public function registerBundles()
{
    $bundles = array(
        // ...
        new GosBundleWebSocketBundleGosWebSocketBundle(),
        new GosBundlePubSubRouterBundleGosPubSubRouterBundle(),
    );
}

下载完成激活完成之后根据我目前遇到的情况需要进行以下操作

删除routing_dev.yml中的

_configurator:
    resource: "@SensioDistributionBundle/Resources/config/routing/webconfigurator.xml"
    prefix:   /_configurator

为了方便后续维护,故将所有配置文件都独立出来 因为使用新建Symfony项目进行研究故目前默认放置在AppBundle中实际情况中请根据实际情况修改本文所说配置

#web_socket.yml

# Web Socket Configuration
gos_web_socket:
    server:
        port: 8080        #The port the socket server will listen on
        host: 127.0.0.1   #The host ip to bind to
        router:
            resources:
                - '@AppBundle/Resources/config/pubsub/routing.yml'
    rpc:
        - '@acme_hello.rpc_sample_service'
    topics:
        - '@acme_hello.topic_sample_service'

在AppBundle中新建以下2个接口 请 点击查看 相关代码

#AppBundleRpcAcmeRpc.php
<?php

namespace AppBundleRpc;

use RatchetConnectionInterface;
use GosBundleWebSocketBundleRPCRpcInterface;
use GosBundleWebSocketBundleRouterWampRequest;

class AcmeRpc implements RpcInterface
{
    /**
     * Adds the params together
     *
     * Note: $conn isnt used here, but contains the connection of the person making this request.
     *
     * @param ConnectionInterface $connection
     * @param WampRequest $request
     * @param array $params
     * @return int
     */
    public function sum(ConnectionInterface $connection, WampRequest $request, $params)
    {
        return array("result" => array_sum($params));
    }

    /**
     * Name of RPC, use for pubsub router (see step3)
     *
     * @return string
     */
    public function getName()
    {
        return 'acme.rpc';
    }
}
#AppBundleTopicAcmeTopic.php
<?php

namespace AppBundleTopic;

use GosBundleWebSocketBundleTopicTopicInterface;
use RatchetConnectionInterface;
use RatchetWampTopic;
use GosBundleWebSocketBundleRouterWampRequest;
use GosBundleWebSocketBundleTopicTopicPeriodicTimer;
use GosBundleWebSocketBundleTopicTopicPeriodicTimerInterface;

class AcmeTopic implements TopicInterface,TopicPeriodicTimerInterface
{
    /**
     * This will receive any Subscription requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic $topic
     * @param WampRequest $request
     * @return void
     */
    public function onSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request)
    {
        //this will broadcast the message to ALL subscribers of this topic.
        $topic->broadcast(['msg' => $connection->resourceId . " has joined " . $topic->getId()]);
    }

    /**
     * This will receive any UnSubscription requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic $topic
     * @param WampRequest $request
     * @return void
     */
    public function onUnSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request)
    {
        //this will broadcast the message to ALL subscribers of this topic.
        $topic->broadcast(['msg' => $connection->resourceId . " has left " . $topic->getId()]);
    }


    /**
     * This will receive any Publish requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic $topic
     * @param WampRequest $request
     * @param $event
     * @param array $exclude
     * @param array $eligible
     * @return mixed|void
     */
    public function onPublish(ConnectionInterface $connection, Topic $topic, WampRequest $request, $event, array $exclude, array $eligible)
    {
        /*
        	$topic->getId() will contain the FULL requested uri, so you can proceed based on that

            if ($topic->getId() === 'acme/channel/shout')
     	       //shout something to all subs.
        */

        $topic->broadcast([
            'msg' => $event,
        ]);
    }


    /**
     * Like RPC is will use to prefix the channel
     * @return string
     */
    public function getName()
    {
        return 'acme.topic';
    }
    /**
     * @var TopicPeriodicTimer
     */
    protected $periodicTimer;

    /**
     * @param TopicPeriodicTimer $periodicTimer
     */
    public function setPeriodicTimer(TopicPeriodicTimer $periodicTimer)
    {
        $this->periodicTimer = $periodicTimer;
    }

    /**
     * @param Topic $topic
     *
     * @return array
     */
    public function registerPeriodicTimer(Topic $topic)
    {
        //add
        $this->periodicTimer->addPeriodicTimer($this, 'hello', 2, function() use ($topic) {
            $topic->broadcast('hello world');
        });

        //exist
        $this->periodicTimer->isPeriodicTimerActive($this, 'hello'); // true or false

        //remove
        $this->periodicTimer->cancelPeriodicTimer($this, 'hello');
    }


}

之后在web_socket.yml中定义的路由地址写入路由配置

acme_topic:
    channel: acme/channel
    handler:
        callback: 'acme.topic' #related to the getName() of your topic

acme_rpc:
    channel: sample/{method}
    handler:
        callback: 'acme.rpc' #related to the getName() or your RPC service
    requirements:
        method:
            pattern: "[a-z_]+" #可接受正则

定义服务

#AppBundleResourcesservices.yml
services:
    acme_hello.topic_sample_service:
        class: AppBundleTopicAcmeTopic
        tags:
            - { name: gos_web_socket.topic }

    acme_hello.rpc_sample_service:
        class: AppBundleRpcAcmeRpc
        tags:
            - { name: gos_web_socket.rpc }

到此为止基础环境就可以进行使用了 在终端运行

php app/console gos:websocket:server 如果一切顺利,您将看到类似于以下内容:

这意味着websocket服务器现在正在运行! 推荐使用 screen 将服务常驻 此bundle也提供了常驻方法 目前还未研究到

实际应用篇

安装客户端Javascript

这一步主要就是为了导入WebSocketBundle中提供的

GosWebSocketBundle/Resources/public/js/vendor/autobahn.min.js
GosWebSocketBundle/Resources/public/js/gos_web_socket_client.js

twig模板中使用

{{ ws_client() }}

作为导入语句你得到的永远是个 错误信息:Unknown “javascripts” tag google得到Yes since symfony2.8 assetic bundle is removed没办法 Symfony中此简单方法是无法使用了将这两个js文件找到并引入页面即可

{% extends 'base.html.twig' %}
{% block stylesheets %}
    <script type="text/javascript" src="{{ asset('assets/js/autobahn.min.js') }}"></script>
    <script type="text/javascript" src="{{ asset('assets/js/gos_web_socket_client.js') }}"></script>
    <script type="text/javascript" src="{{ asset('assets/js/jquery-2.1.1.js') }}"></script>

{% endblock %}
{% block body %}
    <textarea style="width: 120px;height: 60px;" class="content"></textarea>
    <button class="click" style="color: #0000cc">测试按钮</button>
    {#Yes since symfony2.8 assetic bundle is removed#}
    <script type="text/javascript">
        var websocket = WS.connect("ws://127.0.0.1:8080");//连接websocket服务器

        $('body').on('click','.click', function () {
            var content = $('.content').val();
            $.post('{{ path('app_socket_push') }}', {content:content});//测试用接口 推送消息到所有连接客户端中
        });


        websocket.on("socket/connect", function(session){
            session.subscribe("acme/channel", function(uri, payload){
                console.log("Received message", payload.msg);//接收到信息处理方法-请根据实际情况修改
            });
        });

        websocket.on("socket/disconnect", function(error){
            console.log("Disconnected for " + error.reason + " with code " + error.code);//连接失败处理
        });
    </script>
{% endblock %}

服务端实现消息推送

为实现PHP代码推送消息需在web_socket.yml中写入以下配置

gos_web_socket:
    pushers:
        wamp:
            host: 127.0.0.1
            port: 8080

使用

$pusher = $this->container->get('gos_web_socket.wamp.pusher');
//push(data, route_name, route_arguments)
$pusher->push(['my_data' => 'data'], 'user_notification', ['username' => 'user1']);
//user_notification 修改成之前@AppBundle/Resources/config/pubsub/routing.yml中定义的channel: acme/channel的acme_topic参数

进行消息推送

来看下实际效果

完美~

后续单一用户消息推送目前正在研究 未完待续……

转载时请注明出处及相应链接,本文永久地址:http://blog.it985.com/22164.html

微信打赏

支付宝打赏

感谢您对作者Pota的打赏,我们会更加努力!    如果您想成为作者,请点我


用户评论
开源开发学习小组列表