Ratchet onopen client not fire - php

I am trying to implement Ratchet Socket Hello word on my local machine every things works perfectly but on vps centos server when i run server service with
ssh Command : php chat-server.php
it start Listening on port correctly(i can see on linux that port is Listening ) , but when i open "clint.html" page the method onopen never fire but server says
new client connected !
and after 2 minute it says
client disconnected
if i send message to client it will take 2 minutes then client will receive it, but it will disconnect again
it seems to me that there is not stable connection between server and client. every time when i check websocket.readyState its not equal to 1
i disabled firewall and any security on vps server but still have this problem.
i have to mention that normal php socket functions works without problem because i could test it and every thing works
but about ratchet it seems it hang on onopen method.
port 9091 is open
firewall is disabled
abrandao.com/2013/06/websockets-html5-php/ works whiteout problem and can send and receive message from clients
BUT Ratchet has problem onconnect
chat-server.php :
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
9091
);
echo date("Y-m-d H:i:s")." chat-server Started on port 9091 \n";
$server->run();
Chat.php class :
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo date("Y-m-d H:i:s")." New connection! ({$conn->resourceId})\n";
$conn->send("Hello {$conn->resourceId} from server at : ".date("Y-m-d H:i:s"));
echo date("Y-m-d H:i:s")." Hello Sent to ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf(date("Y-m-d H:i:s").'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) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo date("Y-m-d H:i:s")." Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo date("Y-m-d H:i:s")." An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
client html :
$(document).ready(function(){
connect();
});
var wsUri = "ws://myserverdomain.comOrIP:9091";
function connect() {
var ws = new WebSocket(wsUri);
ws.onopen = function() {
var now = new Date();
console.log(now + ' Connected to '+wsUri);
};
ws.onmessage = function(e) {
var now = new Date();
console.log(now + ' Message Recived From Server :', e.data);
};
ws.onclose = function(e) {
var now = new Date();
console.log(now +' Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function() {
connect();
}, 1000)
};
ws.onerror = function(err) {
var now = new Date();
console.error(now + ' Socket encountered error: ', err.message, 'Closing socket')
console.error(err)
ws.close()
};
}

Related

my ratchet websockets noot working on shared server

i am using php ratchet websockets on my shared server on one domain the ratchet websockets is working perfectly but when i run sockets on my other domain it give me some tcp errors both of my domains are on the same server.
That is my socket.php code many time I changes my port number also but nothing happended
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
require 'chat.php';
$loop = React\EventLoop\Factory::create();
// Run the server application through the WebSocket protocol on port 8888
$app = new Ratchet\App("example.com", 8888, '0.0.0.0',$loop);
$app->route('/chat', new Chat, array('*'));
$app->run();
$app->enableKeepAlive($app->loop, 10);
?>
and here is my chat.php code
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
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 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();
}
}
?>
now when i run php socket.php on command line than it is not doing anything and when i run the socket.php url it shows this page isn't workingbelow is my composer.json code
{
"require": {
"cboden/ratchet": "^0.4.2",
"textalk/websocket": "^1.3"
}
}
I also installed mbstring and iconv in my domain.
The error is:
PHP Fatal error: Uncaught RuntimeException: Failed to listen on
"tcp://127.0.0.1:8843": Address already in use in
/home/example.com/public_html/test/rachet/vendor/react/socket/src/TcpServer.php:164

make a multi thread websocket

I made a Websocket server using ratchet and php it works fine but the problem is it's not multi thread and this makes the server replay late when multiple clients send messages to the server at the same time.
I want to know if there is any way to make it multi thread so each connection run on it's own thread or if it's not the right way give me a better one
Thanks!
Chat.php codes:
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
require 'vendor/autoload.php';
require(dirname(dirname(__FILE__)).'/inc/class/class-app_api.php');
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
echo 'server Started!';
}
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');
$obj = new \app_api($from, $msg);
$res = $obj->handleRequest();
if (is_array($res)) {
foreach ($this->clients as $client) {
if ($from != $client) {
// The sender is not the receiver, send to each client connected
$client->send($res['data']);
}
}
}else {
$from->send($res);
}
}
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";
$obj = new \venicehost_app_api($from);
$conn->send($obj->setError('An error has occurred:' . $e->getMessage()));
//$conn->close();
}
}
?>
Server.php codes:
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
require_once("Chat.php");
//require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
port,
ip address
);
$server->run();
?>

Receiving RabbitMQ messages in PHPRatchet

I am trying to achieve mechanism where PHP pushes message to RabbitMQ (I don't want RabbitMQ to be directly exposed to user), RabbitMQ connects to RatchetPHP and Ratchet broadcasts it via websocket connections to users.
The issue I have is with accually making Ratchet server to simultanously listen for queue messages and transfer them further. Ratchet documentation assumes using ZeroMQ and after a long search through outdated documentations and libraries which do not have such methods anymore (eg. React\Stomp) I need fresh eyes from someone who has experience with these solutions.
What I have is pusher.php (standard example from RabbitMQ docs):
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('hello', false, false, false, false);
$msg = new AMQPMessage('Hello World!');
$channel->basic_publish($msg, '', 'hello');
echo " [x] Sent 'Hello World!'\n";
$channel->close();
$connection->close();
Just to simplify reproducing scenario I include also Chat class:
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
class Chat implements MessageComponentInterface
{
protected $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $connection)
{
// Store the new connection to send messages to later
$this->clients->attach($connection);
echo "New connection! ({$connection->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)
{
/** #var \SplObjectStorage $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();
}
}
And Ratchet server.php (standard Ratchet example and RabbitMQ receiver example):
use PhpAmqpLib\Connection\AMQPStreamConnection;
use Src\Chat;
// RABBIT_RECEIVER
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('hello', false, false, false, false);
echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
$callback = function ($msg)
{
echo " [x] Received ", $msg->body, "\n";
};
$channel->basic_consume('hello', '', false, true, false, false, $callback);
while(count($channel->callbacks))
{
$channel->wait();
}
$channel->close();
$connection->close();
// RABBIT_RECEIVER END
$server = new \Ratchet\App('sockets.dev');
$server->route('/', new Chat());
$server->run();
Current versions are basically 2 separate mechanisms listening for messages and they work great alone (so no issue there) except that they block each other and do not transfer messages between.
Question is how to make server.php to make RabbitMQ receive message and plug it into running Ratchet server.
I figured it out so adding answer for posterity. Solution is not fully real time but it is very close, seems to have good performance and is non-blocking for Ratchet websocket server. Solution was in Ratchet custom loop and addPeriodicTimer method.
So code for server.php should look like this:
$loop = React\EventLoop\Factory::create();
$chat = new Chat($loop);
$server = new \Ratchet\App('sockets.dev', 8080, '127.0.0.1', $loop);
$server->route('/', $chat);
$server->run();
And Chat.php class (only __constructor because rest is the same):
public function __construct(LoopInterface $loop)
{
$this->loop = $loop;
$this->clients = new \SplObjectStorage();
$this->loop->addPeriodicTimer(0, function ()
{
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('hello', false, false, false, false);
echo ' [*] Checking for for messages from RabbitMQ', "\n";
$max_number_messages_to_fetch_per_batch = 10000;
do
{
$message = $channel->basic_get('hello', true);
if($message)
{
foreach($this->clients as $client)
{
$client->send($message->body);
}
$max_number_messages_to_fetch_per_batch--;
}
}
while($message && $max_number_messages_to_fetch_per_batch > 0);
$channel->close();
$connection->close();
});
}
Initiating Ratchet server will attach periodic event (in example every 0 sec) which will check RabbitMQ for new messages and process them.
Just for better performance control allowing websocket to take a breath number of messages from RabbitMQ processed in one batch was limited to 10k. Processed messages are removed from queue and next batch is processed in next iteration.
You can also fine tune frequency of updates with addPeriodicTimer interval parameter. 0 seconds is the closest to real time you will get but it may not be required for your needs and can be changed to higher value.

PHP - Combining Websocket Client & Server (Relay)

I want to create a PHP script that connects to a websocket server and then serves the responses from the remote server on a local websocket server. Basically, a websocket relay. I have working client code and I have working server code.
The problem comes when I try to combine the client with the server. I've tried taking my client code and putting it in my server code. It works except that the client is blocking so that if I disconnect from it, I can't reconnect. It happens like this:
I start my code -> server code opens local port and serves websocket -> I connect to local port with websocket testing tool -> client code connects to remote websocket server and relays responses to me -> I disconnect my tool -> client code never returns so server code can't accept new connections anymore.
My code uses the following composer packages:
"cboden/ratchet": "^0.4.0",
"ratchet/pawl": "^0.3.1"
You can see that I have commented out the client part that connects to the remote websocket server. This is the part that blocks.
<?php
// Make sure composer dependencies have been installed
require '../web/vendor/autoload.php';
require_once('../web/usersc/includes/custom_functions.php');
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use WebSocket\Client;
/**
* chat.php
* Send any incoming messages to all connected clients (except sender)
*/
class MyChat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
/*
$loop = React\EventLoop\Factory::create();
$reactConnector = new React\Socket\Connector($loop, [
'dns' => '8.8.8.8',
'timeout' => 10
]);
$connector = new Ratchet\Client\Connector($loop, $reactConnector);
$connector('wss://example.com/websocket', [], ['Origin' => 'http://localhost'])
->then(function(Ratchet\Client\WebSocket $conn) {
$conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
echo "Received: {$msg}\n";
//$conn->close();
});
$conn->on('close', function($code = null, $reason = null) {
echo "Connection closed ({$code} - {$reason})\n";
});
$conn->send('Hello World!');
}, function(\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
});
$loop->run();
*/
}
public function onMessage(ConnectionInterface $from, $msg) {
foreach ($this->clients as $client) {
if ($from != $client) {
$client->send($msg."sdfsfsf");
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$conn->close();
}
}
// Run the server application through the WebSocket protocol on port 8080
$app = new Ratchet\App('localhost', 8080);
$app->route('/chat', new MyChat, array('*'));
$app->run();

Basic react http server and websocket server at the same time

I managed to create a web service that listens on port 80 for http requests and handles ajax calls and also long polling.
But I'm stuck at creating a similar websocke server in the same php file
<?php
require_once('vendor/autoload.php');
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
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);
$conn->send('aa');
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();
}
}
$loop = React\EventLoop\Factory::create();
$swsa=new Chat;
$webSock = new React\Socket\Server($loop);
$webSock->listen(8687, '127.0.0.1'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
$swsa
)
),
$webSock
);
$app = function ($request, $response) {
//some code here to manage requests
$response->writeHead(200,array('Content-Type'=>'application/json'));
$response->end(json_encode(array('ok'=>'ok')));
};
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket, $loop);
$http->on('request', $app);
$socket->listen(8485);
$loop->run();
Code in browser:
var wsUri = "ws://127.0.0.1:8687/";
websocket = new WebSocket(wsUri);
This triggers an error in the browser
Firefox can't establish a connection to the server at ws://127.0.0.1:8687/
Your IoServer initialization is incorrect. If you check the code for IoServer class, you will find:
public function __construct(MessageComponentInterface $app,ServerInterface $socket, LoopInterface $loop = null)
and
public function run() {
if (null === $this->loop) {
throw new \RuntimeException("A React Loop was not provided during instantiation");
}
// #codeCoverageIgnoreStart
$this->loop->run();
// #codeCoverageIgnoreEnd
}
The IoServer class object has no loop assigned to it and hence it fails to execute. Try passing loop as your third argument.

Categories