Can Ratchet WebSocket Server send a message to client itself? - php

I want to use a Ratchet (http://socketo.me) for permanent connection between iPhone Apps and Server. And I need to exchange data between apps and server.
From this example (http://socketo.me/docs/hello-world) I've found out that I have a function onMessage that will be called when the App send a massage to the server and the server could send a response to the App.
But the server also must have an ability to send data to the app without getting data from app. For example, the connection between app and server has been established. Something happened on the server and we need to send a new data to the app. How can I do it and is it possible?
The main question is how can I send data to the App from the server?
Thank you for any help.

That is indeed possible. You need to communicate with the WebSocket server process somehow. You can do that by using some form of message passing, be it RPC or a message queue.
Ratchet itself is based on the React event loop. This means that any form of communication with Ratchet must be integrated with that event loop. On the React homepage you can see some of the integrations that already exist:
Predis/Async (you can use redis pub/sub for message passing)
DNode-PHP (dnode is a TCP based RPC protocol)
React/ZMQ (integrates the event loop with ZeroMQ)
React/Stomp (implementation of the STOMP protocol, allowing you to talk to a message such as RabbitMQ)
JCook21/ReactAMQP (AMQP bindings for React PHP)
In the Ratchet documentation there is a tutorial on how to use React/ZMQ in order to push messages from anywhere to your WebSocket server.

Ratchet also implements WAMP, which includes PubSub. So your clients can subscribe to some topics, and you can have other clients (running i.e. on your backend infrastructure) publish to those topics. You could i.e. have an AutobahnPython based client publishing via Ratchet to an AutobahnAndroid based mobile app or AutobahnJS based HTML5 client.

I had the exact same question and here is what I did.
Based on the hello world tutorial, I have substituted SplObjectStorage with an array. Before presenting my modifications, I'd like to comment that if you followed through that tutorial and understood it, the only thing that prevented you from arriving at this solution yourself is probably not knowing what SplObjectStorage is.
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = array();
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients[$conn->resourceId] = $conn;
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
, $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $key => $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
$client->send($msg);
}
}
// Send a message to a known resourceId (in this example the sender)
$client = $this->clients[$from->resourceId];
$client->send("Message successfully sent to $numRecv users.");
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
unset($this->clients[$conn->resourceId]);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
Of course to make it really useful you may also want to add in a DB connection, and store/retrieve those resourceIds.

Related

How to build a Web Socket Connection?

In my Android project I want to implement Web Sockets. So first I tried to integrate the server-side Websockets and tried to test it in the command line. The following link shows how I tried to open the Web Socket Connection. I tried to reach the Port which is created in the Web socket connection and it worked! But when I attached a message I never receive it. Maybe that’s because the onMessage function is not triggered?
https://i.stack.imgur.com/N8tsf.jpg
Additionally I used following code to open the Websocket connection and send a message.
?php
ini_set('display_errors',1);
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require_once '/var/www/vendor/autoload.php';
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
, $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8081
);
$server->run();
?>
There aren't any errors if I run php app.php. So actually it should work to send a message and receive it? Furthermore the onMessage function doesn't seem to be triggered. But if I add an echo in the public function __construct() function it is printed, so it might be the only function which is executed.
I hope someone can help me to receive and print messages in this Web Socket Connection.
Thanks for your help!
A websocket is a socket, but a socket is not necessarily a websocket. Telnet doesn't work well with testing websockets, because it connects to the socket, but it doesn't do the handshake.
A websocket is basically a socket that requires an http handshake at the beginning before it can begin sending messages. That's why it looks like the Ratchet program isn't responding. It's waiting for your side of the handshake to be done.
To make it work with your server, you would probably want to get a websocket client on the Android side of things. Or, you could make a server which is just a regular socket server instead of a websocket.
If you get the websocket handshake done correctly, before any message is sent, you should see New connection! in the terminal on the php side, because of what you have in the onOpen function.
If you sent something along the lines of this:
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
...it might work.
https://en.wikipedia.org/wiki/WebSocket#Protocol_handshake

How to listener on realtime firebase database for get data dynamically by backend laravel and websocket ,without use javascript

I need to get data from firebase realtime database dynamic with out refresh page so, how to do listener on realtime firebase database for get data dynamically by backend laravel and websocket, not from frontend as javascript.
public function onMessage(ConnectionInterface $conn, $msg)
{
echo $msg;
// $data = json_decode($msg);
$payload = json_decode($msg);
if (method_exists($this, $method = 'handle' . ucfirst($payload->event))) {
$this->{$method}($connection, $payload);
}
// if (isset($data->command)) {
// // $user = $this->users[$conn->resourceId];
// $message = $payload->data;
// }
}
While the Firebase Realtime Database uses web sockets to communicate between the server and its SDKs, this protocol is not documented. The closest you can get with a public API, is to implement Firebase's REST Streaming API.
But you'll have a much easier time if you stick to one of the supported server-side or client-side SDKs. For the server-side such SDKs currently exists for Java, Node.js, Python, and Go.

Ratchet Websocket push integration

I am trying to develop a chat system using Websockets (Ratchet). Until now I have already made a functional PHP based Websocket server that is able to answer on predefined JSON encoded message using the following method.
function onMessage(ConnectionInterface $from, $msg){ ... }
The problem is that I'd like to push messages from the backend database via a background worker/thread to the right client, if something changed in my tables. Is this possible using PHP?
I don't want the client asking the websocket server every 5 minutes to refresh its state as shown below.
{"action":"giveMeUpdates"}
but the webserver should be able to do something like this:
{"status":"newMessages", "messagelist":[...]}
In addition:
class Chat extends ChatActionHandler implements MessageComponentInterface { ... }
this is my class where the ChatActionHandler holds functions for interacting with client requests. With the MessageComponentInterface i can only reply on Socket events like function onOpen(ConnectionInterface $conn). It is runned by the RatchetIO Server:
$server = IoServer::factory(
new Chat(),
8080);
$server->run();
You can attach timer, like cron with
$this->loop->addPeriodicTimer($timeout, function($timer) {});

How to use Ratchet to respond to HTML5 server-side events?

(Note: I've intentionally put non adequate websocket tag here, as it's best chance for WebSocket expert folks to know architecture of Ratchet).
I'm up for implementing HTML5 server side events, and what I need is server side solution. Since hanging Apache's one process per connection (connection pool limit, memory consumption...) is out of consideration I was hoping that Ratchet project can be of help, since it's most maintained project and they have http server coupled along with other components.
My question is: how can I use it? Not for upgrading http request (default usage), but for serving dynamically generated content.
What have I tried so far?
installed Ratchet as explained in tutorial
tested WebSocket functionality - works properly
followed very basic set of instructions given on page that describes http server component:
/bin/http-server.php
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
require dirname(__DIR__) . '/vendor/autoload.php';
$http = new HttpServer(new MyWebPage);
$server = IoServer::factory($http);
$server->run();
One should not be an expert to figure out that MyWebPage class here needs to be declared in order for server to work, but how?
The Ratchet documentation does not seems to cover this.
Your MyWebPage class needs to implement HttpServerInterface. Since it's just going to be a simple request/response you need to send a response and then close the connection within the onOpen() method of your class:
<?php
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
class MyWebPage implements HttpServerInterface
{
protected $response;
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null)
{
$this->response = new Response(200, [
'Content-Type' => 'text/html; charset=utf-8',
]);
$this->response->setBody('Hello World!');
$this->close($conn);
}
public function onClose(ConnectionInterface $conn)
{
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
}
public function onMessage(ConnectionInterface $from, $msg)
{
}
protected function close(ConnectionInterface $conn)
{
$conn->send($this->response);
$conn->close();
}
}
I ended up using the Ratchet\App class instead of Ratchet\Http\HttpServer because it allows you to set up routing among other things, so your /bin/http-server.php would then look like this:
<?php
use Ratchet\App;
require dirname(__DIR__) . '/vendor/autoload.php';
$app = new App('localhost', 8080, '127.0.0.1');
$app->route('/', new MyWebPage(), ['*']);
$app->run();
When you run php bin/http-server.php and visit http://localhost:8080 you should see the Hello World! response in your browser.
This is all you need for a basic request/response system, but it could be extended further by implementing HTML templates and things like that. I've implemented this myself in a little test project which I've uploaded to github along with a lot of other things, including an abstract controller which I can extend for different pages.
Chat server using Ratchet - Basic
Chat server using Ratchet - Advanced
Check the link above. The guy here is using Ratchet to build a real time chat server. He is basically storing usernames initially and then sending/broadcasting to all. You can modify it and check at the time of sending that certain username or uid is active at the moment and send data to them only. You can generate data dynamically and send to particular users or to all. May be this will help.

how can i know username of clients

hi i am writing a simple game with php ,
for this work i use http://socketo.me it have a method "onOpen()" that it is like this code
PHP :
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
i can access to a ConnectionInterface for each clients that it contain a resourceId or a remoteAddress (ipaddress of the client)
but in my application people first login to the web site then they connect to server but the only thing that i have from the clients on the server is a ConnectionInterface how can i know that each $conn is for which user?
In the documentation on the socketo.me web site, there is this page
http://socketo.me/docs/sessions
Each ConnectionInferface has a SessionProvider object. Their example code
// Inside your MyApp class
public function onOpen($conn) {
$conn->send('Hello ' . $conn->Session->get('name'));
}
The session object will have info regarding the logged in user

Categories