varspool / websocket-bundle
PHP WebSocket 客户端/服务器库
Requires
- php: >=5.3
- kwattro/markdown-bundle: dev-master
- symfony/framework-bundle: 2.*
This package is auto-updated.
Last update: 2024-09-09 23:01:20 UTC
README
VarspoolWebsocketBundle
Alpha稳定性。提供WebSocket服务,包括内置服务器、多路复用、语义配置。
在Symfony2中处理WebSocket可能有更好的方式,其中一些方式可能使您甚至不需要第三方包。例如,使用Ratchet所需的代码量很小,您可能决定放弃自定义配置和使用容器来配置服务器。
安装
VarspoolWebsocketBundle依赖于
- Wrench(之前为php-websocket),版本2.0.1+ (varspool/Wrench)
当然,还需要Symfony2。大部分,该包是在WebSocket 2.0之上的一个轻量级兼容层,允许它与服务容器一起使用。
配置依赖项
Composer
如果您使用Composer,请将以下包添加到项目的需求中
{ "require": { "varspool/websocket-bundle": "dev-master", "wrench/wrench": "dev-master" } }
deps文件
如果您使用bin/vendors来配置依赖项,请将以下行添加到您的deps
文件中
[wrench] git=git://github.com/varspool/Wrench.git version=origin/master [VarspoolWebsocketBundle] git=git://github.com/varspool/WebsocketBundle.git target=/bundles/Varspool/WebsocketBundle version=origin/master
或者,首先将其分支到自己的存储库,以便您可以发送pull请求并改进上游👍。完成此操作后,您可以使用bin/vendors
获取包
$ bin/vendors update
[...]
> Installing/Updating wrench
> Installing/Updating VarspoolWebsocketBundle
app/autoload.php
在自动加载器中注册Varspool和Wrench命名空间(如果您使用的是带有Symfony 2.1的Composer则不是必需的)
# app/autoload.php $loader->registerNamespaces(array( // [...] 'Varspool' => __DIR__.'/../vendor/bundles', 'Wrench' => __DIR__.'/../vendor/wrench/lib' ));
app/AppKernel.php
注册VarspoolWebsocketBundle
# app/AppKernel.php public function registerBundles() { $bundles = array( //... new Varspool\WebsocketBundle\VarspoolWebsocketBundle(), ); }
使用
服务器端以服务器启动
任何PHP进程只能运行一个WebSocket服务器,为可变数量的客户端提供服务。性能未测试,一旦进入生产阶段,您可能需要替换服务器端。(下面的多路复用接口可能会有所帮助:在您的PHP应用程序代码和轻量级WebSocket服务器之间放置一个消息队列。)
要启动服务器,该包提供了一个websocket:listen
控制台命令,可以通过app/console
访问
Usage:
websocket:listen [server_name]
Arguments:
server_name The server name (from your varspool_websocket configuration) (default: default)
listen命令接受一个必需的参数:要使用的服务器配置名称。服务器定义在您的Symfony2配置中,无论是YAML、XML还是PHP。您必须至少定义一个以开始(我们建议“默认”)。以下是一个定义的例子
varspool_websocket: servers: default: # Server name listen: ws://192.168.1.103:8000 # default: ws://:8000 # Applications this server will allow applications: - echo - multiplex # Origin control check_origin: true allow_origin: # default: just localhost (not useful!) - "example.com" - "development.localdomain" # Other defaults max_clients: 30 max_connections_per_ip: 5 max_requests_per_minute: 50
一旦配置了服务器,运行websocket:listen命令。当它运行时,服务器将启动并为您配置中定义的应用程序提供服务。
应用程序
服务器本身不做任何事情,直到您为它编写一个应用程序。一旦应用程序注册,服务器就会调用您应用程序上的方法。
注册您应用程序很容易。服务器寻找标记为varspool_websocket.application
的服务。因此,要运行应用程序,导出一个带有该标记的服务。
单个服务器守护进程可以为一到多个应用程序提供服务。因此,您还必须在您的标记中包含一个key
属性。这最终会显示在您的应用程序URL中。例如,如果您使用以下服务定义
<!-- Application\ChatBundle\Resources\config\services.xml --> <service id="chat_service" class="Application\ChatBundle\Services\ChatService"> <tag name="varspool_websocket.application" key="chat" /> </service>
并且您的服务器配置为监听192.168.1.10:8000,那么您应用程序的URL将是
ws://192.168.1.10:8000/chat
除非在服务器配置中指定,否则不会在服务器上注册应用程序。因此,要启用默认服务器上的上述应用程序,您的配置需要包含
# app/config.yml
varspool_websocket:
servers:
default:
# ...
applications:
- chat
以下是一个另一个服务定义的例子,这次是YAML格式
services: websocket_example: class: Application\ExampleBundle\Application\ExampleApplication tags: - { name: varspool_websocket.application, key: foobar }
关于一个简单应用的例子,请参阅Application\EchoApplication
。
我建议您让您的应用程序类继承Varspool\WebsocketBundle\Application\Application
,但这不是必须的。会进行一点类型检查,看看您的应用程序是否需要日志记录支持,但仅此而已。所以,您可以自由地扩展任何您喜欢的类:只需实现一个兼容的接口。(这是php-websocket迄今为止采取的方法:提供了一个抽象的WebSocket\Application
类,但服务器不进行类型检查。)
最后,这里展示了运行时定义了一些服务后的监听命令的示例
$ app/console websocket:listen default
info: Listening on 192.168.1.103:8080 with ssl off
info: Server created
info: Registering application: test (Application\TestBundle\Application\TestApplication)
info: Registering application: auth (Application\TestBundle\Application\AuthApplication)
info: Registering application: multiplex (Varspool\WebsocketBundle\Application\MultiplexApplication)
info: Registering application: echo (Varspool\WebsocketBundle\Application\EchoApplication)
客户端
当然,您需要一个支持websockets的浏览器。
至于JavaScript库,这主要取决于您。但除非您已经在使用Coffeescript,否则您可能会发现php-websocket附带的一些库安装起来很麻烦。
多路复用
我建议您多路复用您的JavaScript组件的连接。SockJS实现这种方法的https://rabbitmq.cn/blog/2012/02/23/how-to-compose-apps-using-websockets/
非常优雅,并且由这个包附带的应用程序支持。
客户端多路复用
这个包与SockJS websocket-multiplex前端库使用的多路复用协议兼容。sockjs/websocket-multiplex提供下载。它们甚至还有一个方便的CDN。
<script src="http://cdn.sockjs.org/websocket-multiplex-0.1.js"></script>
这个JavaScript库提供了一个WebSocketMultiplex
对象。您可以给它提供任何与原生的WebSocket
兼容的对象。所以,一开始您可以给它提供一个原生的WebSocket,然后,当您决定安装一个SockJS服务器(或者PHP中已经实现了)时,您可以给它提供一个SockJS对象。所以,像这样
var url = 'ws://example.com:8000/multiplex'; var socket; if (window.MozWebSocket) { socket = new MozWebSocket(url); } else if (window.WebSocket) { socket = new WebSocket(url); } else { throw "No websocket support detected" } socket.binaryType = 'blob'; var real_socket = new WebSocket(url); var multiplexer = new WebSocketMultiplex(real_socket); var foo = multiplexer.channel('bar'); // foo.send(), events: open, close, error, message var logs = mutliplexer.channel('log_server'); // logs.send(), events: open, close, error, message
服务器端多路复用
这个包的默认配置(在Varspool/WebsocketBundle/Resources/config/services.xml中)定义了一个键为"multiplex"的服务器端多路复用应用程序。请确保这个键已列在您的配置中,作为服务器允许的应用程序之一。
当您使用由服务器运行的multiplex应用程序时,您的套接字被进一步抽象为channels,由一个topic字符串标识。所有服务器端的channel监听器都会通知来自客户端的每个消息。监听器可以决定仅回复发送消息的客户端,或者回复订阅了该channel的所有客户端。
- 客户端不能向其他客户端发送消息,除非您明确地中继它们。
- Channel提供了一个方便的抽象来做这件事:
$channel->send('foo', 'text', false, array('except' => $client))
- Channel提供了一个方便的抽象来做这件事:
- 监听器不能向其他监听器发送消息。
- 但您可以使用任何喜欢的方法:监听器可以被注入到服务容器中。
Listener/ConnectionListener接口
在服务器端,您只需要实现Multiplex\Listener
,以便能够监听channel上的事件
/** * @param Channel $channel The channel is an object that holds all the active * client connections to a given topic, and all the server-side * subscribers. You can ->send($message) to the channel to broadcast * it to all the subscribed client connections. ->getTopic() identifies * the topic the message was received on. * * @param string $message The received message, as a string * * @param Connection $client The client connection the message was received * from. You can ->send($string) to the client, but it is a raw Websocket * connection, so if you want to send a multiplexed message to a single * client, you'll probably use * `Varspool\WebsocketBundle\Multiplex\Protocol::toString($type, $topic, $payload)` * and the Protocol::TYPE_MESSAGE constant. */ public function onMessage(Channel $channel, $message, Connection $client);
然后只需为您的服务添加varspool_websocket.multiplex_listener
标签和您想监听的topic
<service id="example.custom" class="Application\ExampleBundle\Services\CustomService"> <tag name="varspool_websocket.multiplex_listener" topic="chat" /> </service>
完成了。您的onMessage
方法将被调用,并提供客户端发送到您指定的multiplex topic的消息的详细信息。您可能还希望做一些事情,当客户端连接到(实际上,订阅)和从您的服务断开连接(无论是真正的断开连接还是取消订阅)时。为此,实现额外的Multiplex\ConnectionListener
接口。
use Varspool\WebsocketBundle\Multiplex\Listener; use Varspool\WebsocketBundle\Multiplex\ConnectionListener; use Varspool\WebsocketBundle\Multiplex\Channel; use Wrench\Connection; class GameServer implements Listener, ConnectionListener { public function onMessage(Channel $channel, $message, Connection $client) { $client->send('Hello, player!'); $channel->send('Oh, wow, guys...' . $client->getClientId() . ' is here'; } public function onConnect(Channel $channel, Connection $client) { $client->send('Welcome to the dungeon'); } public function onDisconnect(Channel $channel, Connection $client) { $channel->send($client->getClientId() . ' is leaving! OH NOES!'); } }
MultiplexService父服务
为了方便起见,如果您想实现这两个接口以及一些其他有用的功能(例如获取服务器或mulitplex应用程序实例的访问权限),只需扩展Services\MultiplexService
,并在您的配置中将其导出为varspool_websocket.multiplex_service
的父服务。
这是在YAML中的样子(额外:多个channel监听器)
# config.yml services: example.websocket_auth: class: Application\ExampleBundle\Services\AuthService parent: varspool_websocket.multiplex_service tags: - name: varspool_websocket.multiplex_listener topic: auth - name: varspool_websocket.multiplex_listener topic: login