WebSocket server with tags management, forward messages on the right clients with ease !
The Gomoob WebSocket server is a simple Ratchet server which works with custom tagsto easily forward messages to clients depending on custom tags.
As an example let's suppose we have a Web Application with English and French users. English users should receiveEnglish messages, French users should receive French messages.
Each application opens a Web Socket with a particular language
tag.
// Web Application in English mode
var enWebSocket = new WebSocket('ws://localhost:8080?tags={"language":"EN}');
...
// Web Application in French mode
var frWebSocket = new WebSocket('ws://localhost:8080?tags={"language":"FR}');
...
On server side the Gomoob WebSocket server keeps track of the associations between tags and WebSocket connections. Forexample this simple PHP peace of code allows to easily forward a message to all clients connected with the language=FR
tag.
// PHP Server (in most cases a Web Server) to Web Socket server client, allows to send one message which is forwared to
// several opened WebSocket connections
$phpClient = new WebSocketClient('ws://localhost:8080');
$phpClient->send(WebSocketRequest::create($message, ['language' => 'FR']);
Running a server requires only one line of code.
require __DIR__ . '/vendor/autoload.php';
echo "WebSocket server started, enter Ctrl+C to stop server." . PHP_EOL;
\Gomoob\WebSocket\Server\WebSocketServer::factory()->run();
First pull the project with composer using the following dependency.
{
"require": {
"gomoob/php-websocket-server": "^1.0.0"
}
}
Then simply use the \Gomoob\WebSocket\Client\WebSocketClient
class to send your messages.
// Open a Server / Server WebSocket connection
$phpClient = new WebSocketClient('ws://localhost:8080');
// Forward a message to all the WebSocket client connections associated to 'tag1' and 'tag2'
$response = $phpClient->send(
WebSocketRequest::create(
$message,
[
'tag1' => 'tag1Value',
'tag2' => 'tag2Value'
]
)
);
If you want to write solid unit tests we also provide the \Gomoob\WebSocket\Client\WebSocketClientMock
class. This class is a utility mock which is very easy to use.
// Somewhere in our code we use a \Gomoob\WebSocket\IWebSocketClient ...
// We suppose this code is implemented in MyPowerfulService->serviceMethod();
$phpClient->send(WebSocketRequest::create('Message 0.')->setTags(['tag0' => 'tag0Value']));
$phpClient->send(WebSocketRequest::create('Message 1.')->setTags(['tag1' => 'tag0Value']));
$phpClient->send(WebSocketRequest::create('Message 2.')->setTags(['tag0' => 'tag0Value', 'tag1' => 'tag1Value']));
// Then we write a test case by replacing the real WebSocket client implementation with the mock one
class SampleTestCase extends TestCase
{
public function setUp() {
$this->webSocketClient = new WebSocketClientMock();
$this->myPowerfulService->setWebSocketClient($this->webSocketClient);
}
public function testServiceMethod() {
// Calls the method to test
$this->myPowerfulService->serviceMethod();
// Checks the right requests were sent
$webSocketRequests = $this->webSocketClient->findByTags(['tag0' => 'tag0Value']);
$this->assertCount(2, $webSocketRequests);
$this->assertContains($webSocketRequest0, $webSocketRequests);
$this->assertNotContains($webSocketRequest1, $webSocketRequests);
$this->assertContains($webSocketRequest2, $webSocketRequests);
}
}
The default behavior of the Gomoob WebSocket server is the following !
8080
and authorize connections from all IP addresses (i.e 0.0.0.0
) ;If one of those behaviors does not fit your need please read the following sub sections. You can also read the src/test/server.php
file which shows how to start a server with custom message parsing and authorizations.
By default the WebSocket server will accept plain string messages, if you try to send a JSON object then you'llencounter the following exception.
The 'message' property is not a string, you must configure a message parser to parse messages !
This is the expected behavior, if you want the server to manage custom PHP object messages then you have to :
\JsonSerializable
and implement the jsonSerialize()
methodcorrectly ;A sample message object is provided in the \Gomoob\WebSocket\Message\Message
class, feel free to read theassociated source code to understand how it works. You'll also found a sample message parser in the \Gomoob\WebSocket\Message\MessageParser
.
To explain how to manage custom PHP object messages let's suppose we have the following message object to send.
class MyMessage {
private $messageProperty1;
public function __construct($messageProperty1) {
$this->messageProperty1 = $messageProperty1;
}
public function getMessageProperty1() {
return $this->messageProperty1;
}
}
Sending such a message in a browser on Javascript would require the following code.
var socket = new WebSocket('ws://localhost:8080');
socket.send(
JSON.stringify(
{
message : {
messageProperty1 : "Hello !"
},
tags : {
tag1 : 'tag1Value'
}
}
)
);
Or in PHP with the client we provide.
WebSocketClient::factory('ws://localhost:8080')->send(WebSocketRequest::create(new MyMessage('Hello !')));
As this this will not work because on server side the Gomoob WebSocket server will not know how to parse the messagesand how to re-create those messages to forward them to clients who opened WebSocket connections.
The first thing to do is to implement the \JsonSerializable
class and the jsonSerializeMethod()
in ourMyMessage
class.
class MyMessage implements \JsonSerializable {
...
public function jsonSerialize() {
return [
'messageProperty1' => $this->messageProperty1;
];
}
}
Then we have to implement a message parser by extending the \Gomoob\WebSocket\IMessageParser
class.
use Gomoob\WebSocket\IMessageParser;
class MyMessageParser implement IMessageParser {
public function parse(array $arrayMessage)
{
// Ensure the array contains only valid key names
foreach (array_keys($arrayMessage) as $key) {
if (!is_string($key) || !in_array($key, ['messageProperty1'])) {
throw new \InvalidArgumentException('Unexpected property \'' . $key . '\' !');
}
}
// The 'messageProperty1' property is mandatory
if (!array_key_exists('messageProperty1', $arrayMessage)) {
throw new \InvalidArgumentException('No \'messageProperty1\' property found !');
}
return new MyMessage($arrayMessage['messageProperty1']);
}
}
Finally we have to provide our parser when we create our WebSocket server.
WebSocketServer::factory(
[
'messageParser' => new MyMessageParser()
]
)->run();
By default the WebSocket server will accept all connections and message sendings, in most cases this behavior is notexpected because anybody could open a WebSocket on your server and try to forward messages to all connected clientswithout authorization.
You can implement a custom authorization manager by implementing the \Gomoob\WebSocket\IAuthManager
interface, this interface has the following signature.
/**
* Interface which defines an authorization manager. An authorization manager allows to control authorization while
* opening Web Socket connections and sending messages over Web Sockets.
*
* @author Baptiste Gaillard (baptiste.gaillard@gomoob.com)
*/
interface IAuthManager
{
/**
* Function used to indicate if connection opening is authorized.
*
* @param \Ratchet\ConnectionInterface $connection the current Ratchet connection.
*
* @return boolean `true` if the connection opening is authorized, `false` otherwise.
*/
public function authorizeOpen(ConnectionInterface $connection);
/**
* Function used to indicate if message sending is authorized.
*
* @param \Ratchet\ConnectionInterface $connection the current Ratchet connection.
* @param \Gomoob\WebSocket\IWebSocketRequest $webSocketRequest the current Gomoob WebSocket request.
*/
public function authorizeSend(ConnectionInterface $connection, IWebSocketRequest $webSocketRequest);
}
So its very easy to manage authorizations, just return true
or false
with the authorizeOpen(...)
orauthorizeSend(...)
functions.
ApplicationsAuthManager
To easier authorization we provide an authorization manager which allows to declare several applications with key
and secret
properties.
This authorization manager is available in the \Gomoob\WebSocket\Auth\ApplicationsAuthManager
class, itworks with a very simple YAML configuration file.
Here is a sample instanciation of the manager with a WebSocket server.
WebSocketServer::factory(
[
'authManager' => ApplicationsAuthManager::factory(
[
'authorizeOpen' => false,
'configurationFile' => __DIR__ . '/auth.yml'
]
)
]
)->run();
The content of the auth.yml
file could be the following.
applications:
-
key: application1
secret: B4ajW3P7jfWEYPZsQV8mnteHg97G67uW
authorizeOpen: true
- key: application2
secret: 33yLWdynhaqm9tYjDFKf8gB8zmAPKdDP
authorizeOpen: false
Then the followig Javascript peace of code will apply.
// Does not work because required 'key' and 'secret' URL parameters are not provided
var socket1 = new WebSocket('wss://myserver.org:8080');
// Works because the 'key' and 'secret' URL parameters provided are valid
var socket2 = new WebSocket('wss://myserver.ord:8080?key=application1&secret=B4ajW3P7jfWEYPZsQV8mnteHg97G67uW');
// Does not work because the request does not provide the 'key' and 'secret' properties
socket2.send(
JSON.stringify(
{
message : {
messageProperty1 : "Hello !"
}
}
)
);
// Works because the request provides valid 'key' and 'secret' properties
socket2.send(
JSON.stringify(
{
message : {
messageProperty1 : "Hello !"
},
metadata : {
key : 'application2',
secret : '33yLWdynhaqm9tYjDFKf8gB8zmAPKdDP'
}
}
)
);
The same rules are also applicable with the PHP client we provide.
WebSocketClient::factory('ws://localhost:8080')->send(
WebSocketRequest::create(
new MyMessage('Hello !')
)->setMetadata(
[
'key' => 'application2',
'secret' => '33yLWdynhaqm9tYjDFKf8gB8zmAPKdDP'
]
)
);
To help you start quickly we also provide a Docker container here https://hub.docker.com/r/gomoob/php-websocket-server.
TagsTree
class to \Gomoob\WebSocket\Util\TagsTree
;TagsTree->reset()
method ;\Gomoob\WebSocket\Client\WebSocketClientMock
class to easier unit testing ;metadata
inthe \Gomoob\WebSocket\IWebSocketRequest
interface and the\Gomoob\WebSocket\Request\WebSocketRequest
class ;defaultMetadata
in the \Gomoob\WebSoscket\IWebSocketClient
interface and the\Gomoob\WebSocket\Client\WebSocketClient
class ;defaultTags
in the \Gomoob\WebSocket\IWebSocketClient
interface and the\Gomoob\WebSocket\Client\WebSocketClient
class ;\Gomoob\WebSocket\Message\Message
serialization ;\Gomoob\WebSocket\Request\WebSocketRequest
serialization ;factory(...)
method or an alias create(...)
method.port
and address
options problems while creating a WebSocketServer
, the parameter were nottransmitted to the Ratchet server ;80
which is the default Ratchet server port.symfony/yaml
composer dependency, otherwise problems was encountered while runningcomposer update --no-dev
;monolog/monolog
composer dependency, , otherwise problems was encountered while runningcomposer update --no-dev
.At Gomoob we build high quality software with awesome Open Source frameworks everyday. Wouldyou like to start your next project with us? That's great! Give us a call or send us an email and we will get back toyou as soon as possible !
You can contact us by email at contact@gomoob.com or by phone number(+33) 6 85 12 81 26 or (+33) 6 28 35 04 49.
Visit also http://gomoob.github.io to discover more Open Source softwares we develop.
我跟随 rfc6455: Concretely, if as in the example above, the |Sec-WebSocket-Key| header field had the value “dGhlIHNhbXBsZSBub25jZQ==”, the server would concatenate the string “258EAFA5-E914-47DA-95CA-C5A
哥,我的也是这样,请问怎么设置? // 以websocket协议连接远程websocket服务器 $wssUrl = 'ws://tts-api.xfyun.cn:443/v2/tts?authorization=YXBpX2tleT0iNGMzZDc2MjBlOTI3MmYyNmI1OTY0ZWM0ZmI0MGVkYjQiLGFsZ29yaXRobT0iaG1hYy1zaGEyNTYiLGhlY
1. websocket是什么 Websocket是html5提出的一个协议规范,参考rfc6455。 websocket约定了一个通信的规范,通过一个握手的机制,客户端(浏览器)和服务器(webserver)之间能建立一个类似tcp的连接,从而方便c-s之间的通信。在websocket出现之前,web交互一般是基于http协议的短连接或者长连接。 WebSocket是为解决客户端与服务端实时通信
搭建简易websocket ------------------ # 1 . 安装swoole扩展 ubuntu查看安装php 的swoole插件 > php -m 如果有swoole就表示已经安装swoole扩展,直接看2 未安装则执行 * cd ~ * wget -c https://github.com/swoole/swoole-src/archive/v2.0.6.tar.gz * cd
什么是WebSocket WebSocker协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信-允许服务器主动发送信息给客户端。 为什么需要WebSocket 缺陷:HTTP的通信只能由客户端发起 WebSocker特点 建立在TCP协议之上 性能开销小通信高效 客户端可以与任意服务器通信 协议标识符ws wss 持久化网络通信协议 ws_server
think-swoole使用教程 核心思想是swoole只是作为一个消息转发器,业务逻辑还是通过接口来实现,发送消息也是使用接口,客服端websocket只负责创建和监听接受消息即可。 环境 centos8 PHP7.4 thinkphp6 开发过程 安装think-swoole扩展 为了方便我们安装think-view扩展 配置swoole.php文件 server.host 服务器IP ser
PHP WebSocket是一个简单的 WebSocket服务器的PHP实现,遵循WebSocket RFC的draft75和draft76规范。支持Flash Socket Policy请求。整个服务器采用模块化设计,非常易于扩展。 客户端代码示例: var server = new WebPush('ws://localhost:8000/echo'); server.bind('open',
本文向大家介绍php中使用websocket详解,包括了php中使用websocket详解的使用技巧和注意事项,需要的朋友参考一下 在PHP中,开发者需要考虑的东西比较多,从socket的连接、建立、绑定、监听等都需要开发者自己去操作完成,对于初学者来说,难度方面也挺大的,所以本文的思路如下: 1、socket协议的简介 2、介绍client与server之间的连接原理 3、PHP中建立socke
问题内容: 我有一个棘手的聊天服务器文件 我使用Websocket进行连接,效果很好 我想要安全连接,因此我尝试使用SSL连接,但无法正常工作。 我的问题是 如何将Websocket与SSL连接连接 任何的想法? 问题答案: 如果您使用的是Apache Web服务器(2.4或更高版本),请在httpd.conf文件中启用以下模块: mod_proxy.so mod_proxy_wstunnel.s
我目前正在开发一个PHP应用程序,它将使用websockets进行客户机-服务器通信。我多次听说PHP不应该用于服务器应用程序,因为缺乏线程机制、内存管理(循环引用)或不方便的套接字库。 到目前为止,一切都工作得相当好。我使用phpws作为websocket库和DBAL来访问不同的数据库系统;PHP版本是5.3.8。服务器最多可服务30个客户端。然而,特别是在最近几天,我读了几篇文章,指出PHP对