Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending messages from PHP script to multiple Ratchet Websocket apps (via ZMQ Socket)

So, I am running a Ratchet (php) websocket server with multiple routes that connect do multiple Ratchet apps (MessageComponentInterfaces):

//loop 
$loop   = \React\EventLoop\Factory::create();

//websocket app
$app = new Ratchet\App('ws://www.websocketserver.com', 8080, '0.0.0.0', $loop);

/*
 * load routes
 */
$routeOne = '/example/route';
$routeOneApp = new RouteOneApp();
$app->route($routeOne, $routeOneApp, array('*'));

$routeTwo = '/another/route';
$routeTwoApp = new AnotherApp();
$app->route($routeTwo, $routeTwoApp, array('*'));

From here I am binding a ZMQ socket, in order to be able to receive messages sent from php scripts run on the normal apache server.

// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new \React\ZMQ\Context($loop);
$pull = $context->getSocket(\ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5050'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', array($routeOneApp, 'onServerMessage'));

Finally, the server is started:

//run
$loop->run();

This works perfectly fine as long as i am binding only one of the ratchet apps to the ZMQ socket. However, i would like to be able to separately push messages to both of the Ratchet apps. For this purpose i thought of binding two ZMQ sockets to different routes like:

$pullOne->bind('tcp://127.0.0.1:5050' . $routeOne); // Binding to 127.0.0.1 means the only client that can connect is itself
$pullOne->on('message', array($routeOneApp, 'onServerMessage'));

and

$pullTwo->bind('tcp://127.0.0.1:5050' . $routeTwo); // Binding to 127.0.0.1 means the only client that can connect is itself
$pullTwo->on('message', array($routeTwoApp, 'onServerMessage'));

However, this leads to an error message from ZMQ when binding the second socket, saying the given address is already in use.

So the question is, is there any other way to use routes over a ZMQ socket? Or should i use other means to distinguish between messages for the separate Ratchet apps, and if so, what would be a good solution? I thought about binding to 2 different ports, but figured that would be a pretty ugly solution?!

like image 970
Erik Verboom Avatar asked Feb 07 '17 17:02

Erik Verboom


1 Answers

In general in TCP packets are identified by the 4 tuple (sender ip, sender port, receiver ip, receiver port).

When a incoming packet reaches the network layer, it is forwarded to the appropriate application by looking at the receiver ip and port. If you use the same pair for both the apps, it will be impossible for the layer to decide whom to send it to when a connection comes in.

One solution would be to bind a single connection and the write a common handler that looks at the incoming content and then decides (I assume you have some logic) to differentiate the incoming connections to the different instances and then invokes the corresponding handler. The handler can get the connection object and can handle the connection hence forth.

If both your instances are identical and it doesn't matter who gets the request then you can just randomly forward the new connection to any of the handler.

Edit: I have tried to answer the question irrespective of the application type (Racket/ZMQ etc) because the issue you are trying to address is a fundamental one common to any network application.

For this case since you have two apps running and want to listen on the same port, you can have a common handler which can look at the request URL and forward the connection to the appropriate handler.

The request URL can be obtained using

$querystring = $conn->WebSocket->request->getQuery();

Now the clients can connect using

ws://localhost:5050/app1 
and
ws://localhost:5050/app2

Your different apps can now handle these connections separately.

like image 173
Ajay Brahmakshatriya Avatar answered Nov 19 '22 17:11

Ajay Brahmakshatriya