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
Related
I have a URI that works well with a js implementation, built as: "wss://domain"
When I want to implement a subscriber for this socket as below:
$loop = Factory::create();
$connector = new Connector($loop);
$promise = $connector->connect($uri);
$promise->then(function(ConnectionInterface $connection) {
$connection->on('data', function ($data) {
echo $data;
});
}, function (\Exception $e) {
echo $e->getMessage();
});
$loop->run();
The promise catches the exception with the message: "No connector available for URI scheme "wss"% "
I can't find any connector for wss. Is there any connectors that I can use directly? Or should I wrap with another connector?
Hey ReactPHP core maintainer here, react/socket only supports low level connections like UDP, TCP etc where you have to implement the protocols on that connection. react/http does that for HTTP, and https://github.com/ratchetphp/Pawl is a WebSocket client for ReactPHP, which builds on top of those two mentioned earlier
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) {});
I'm currently working on a PHP application that will be using some websocket connections to talk to another service.
To talk to this websocket service, we are using Ratchet - which is a PHP library based on react PHP.
This piece of code needs to send and respond to a couple of requests, and after that, should return the information to the "main thread".
Example flow:
HTTP request -> controller -> Starts a service which opens a websocket client -> websocket client is talking to server -> once its done it should return the outcome to the controller code -> controller outputs to user
The issue I'm having is that I'm not familiar with Reactive PHP and am not sure how to handle this.
I've tried;
$service = new WebsocketService();
$startTimer = time();
$service->getList(44);
while($service->getResponse() == null) {
usleep(500);
if (time() > $startTimer + 10) {
continue; //Timeout on 10 seconds
}
}
var_dump($service->getResponse());
The service code would set its "response" variable to something other than null once its done. This obviously fails, because the sleep method is blocking the thread. Also without, it seems like the while loop is blocking I/O and the reactive code fails.
A solution would be to open up a new thread and run the websocket code there, but I wouldn't be happy with that.
I feel like I need to implement some sort of "watcher" around the websocket process, but I'm not sure how to do that.
Our Websocket service client code looks like this;
private $response = null;
/**
* #return null|object
*/
public function getResponse() {
return $this->response;
}
public function getList($accountId) {
$this->response = null;
\Ratchet\Client\connect('ws://192.168.56.1:8080')->then(function(\Ratchet\Client\WebSocket $conn) use ($accountId) {
$login = new \stdClass();
$login->action = 'login';
$conn->on('message', function($msg) use ($conn, $login, $accountId) {
try {
$response = json_decode($msg);
if ($response->result_id == 100) {
//Succesfully logged in to websocket server
//Do our request now.
$message = new \stdClass();
$message->target = 'test';
$conn->send(json_encode($message));
}
if (isset($response->reply) && $response->reply == 'list') {
$this->response = $response; //This is the content I need returned in the controller
$conn->close(); //Dont need it anymore
}
} catch (\Exception $e) {
echo 'response exception!';
//Do nothing for now
}
});
$conn->send(json_encode($login));
}, function ($e) {
echo "Could not connect: {$e->getMessage()}\n";
});
}
Running the code like this also does not work;
$service = new WebsocketService();
$service->getList(44);
echo 'Test';
var_dump($service->getResponse());
because the "test" echo comes before I even get a response from the websocket server.
Please, enlighten me! I'm not sure what to search for.
PHP and websockets still seem to be a bit experimental. Nevertheless I have found a great tutorial on medium.com, written by Adam Winnipass which should be really helpful for solving your problem: https://medium.com/#winni4eva/php-websockets-with-ratchet-5e76bacd7548
The only difference is that they are implementing their websocket client with JavaScript instead of PHP. But in the end there should not be much of a difference, because as soon as we have opened the Websocket connection of each end both applications have to send and also wait to receive notifications - this is how they illustrate it:
Seems like one possibility to create a successful Websocket connection is to extend the MessageComponentInterface
use Ratchet\MessageComponentInterface;
which also requires
use Ratchet\ConnectionInterface;
The message component interface defines the following methods:
onOpen
onMessage
onClose
onError
And I think this is how the Ratchet library is implementing it. This is how they are finally starting their server:
use Ratchet\Server\IoServer;
use MyApp\MyCustomMessageComponentInterface;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new MyCustomMessageComponentInterface()
)
),
8080
);
$server->run();
With this architecture you already can receive (onMessage) and sending is also possible with the send() method.
I can not solve the exact problem with your existing code. But I guess if you are using the pre-built classes and interfaces of the library as intended (and demonstrated here) you should be able to achieve what you want by adding your code to the corresponding methods.
More information and examples can be found in the docs:
http://socketo.me/docs/server
http://socketo.me/api/namespace-Ratchet.html
Are you extending class with WsServer, This might be issue, if you are getting fatal errors. I am not sure whether you are getting fatal errors or warnings. Also i notice the public function onOpen() opens a connection. Please try referring this document http://socketo.me/api/class-Ratchet.WebSocket.WsServer.html might be useful.
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
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.