【问题标题】:Sending messages from PHP script to multiple Ratchet Websocket apps (via ZMQ Socket)从 PHP 脚本向多个 Ratchet Websocket 应用程序发送消息(通过 ZMQ Socket)
【发布时间】:2017-06-25 01:18:18
【问题描述】:

所以,我正在运行一个 Ratchet (php) websocket 服务器,它有多个连接多个 Ratchet 应用程序 (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('*'));

从这里我绑定一个 ZMQ 套接字,以便能够接收从在普通 apache 服务器上运行的 php 脚本发送的消息。

// 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'));

终于启动服务器了:

//run
$loop->run();

只要我只将其中一个棘轮应用程序绑定到 ZMQ 套接字,它就可以正常工作。但是,我希望能够分别将消息推送到两个 Ratchet 应用程序。为此,我想将两个 ZMQ 套接字绑定到不同的路由,例如:

$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'));

$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'));

但是,当绑定第二个套接字时,这会导致来自 ZMQ 的错误消息,指出给定地址已在使用中。

所以问题是,有没有其他方法可以通过 ZMQ 套接字使用路由? 或者我应该使用其他方式来区分单独的 Ratchet 应用程序的消息,如果是这样,什么是一个好的解决方案? 我想过绑定到 2 个不同的端口,但认为这将是一个非常丑陋的解决方案?!

【问题讨论】:

  • 您确定要在 PULL 中使用 bind() 吗?通常在 ZMQ 中,PUSH 端 binds(),PULL 端 connect()。
  • 好问题,我从网上找到的一些教程中复制了绑定,它似乎有效。我会看看 connect() 是否也有效。

标签: php zeromq ratchet phpwebsocket


【解决方案1】:

一般在 TCP 数据包中由 4 个元组(发送方 ip、发送方端口、接收方 ip、接收方端口)标识。

当传入的数据包到达网络层时,通过查看接收方的 ip 和端口将其转发到适当的应用程序。如果您对两个应用程序使用相同的配对,则该层将无法决定在连接进入时将其发送给谁。

一种解决方案是绑定单个连接并编写一个通用处理程序,该处理程序查看传入内容,然后决定(我假设您有一些逻辑)区分传入连接到不同实例,然后调用相应的处理程序.处理程序可以获取连接对象,然后可以处理连接。

如果您的两个实例是相同的,并且无论谁收到请求都无关紧要,那么您可以将新连接随机转发到任何处理程序。

编辑:无论应用程序类型(Racket/ZMQ 等)如何,我都试图回答这个问题,因为您试图解决的问题是任何网络应用程序都常见的基本问题。

对于这种情况,因为您有两个应用程序正在运行并希望在同一个端口上侦听,您可以拥有一个通用处理程序,它可以查看请求 URL 并将连接转发到适当的处理程序。

可以使用获取请求地址

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

现在客户端可以使用连接

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

您的不同应用现在可以分别处理这些连接。

【讨论】:

  • 让我质疑的是,Ratchet 使用了多个绑定到同一个端口的“应用程序”。显然,它们都连接到同一个 websocket,并使用 ID 或其他方法发送。事实上,编写自己的 JSON 协议来根据 AppID 或类似的东西发送消息几乎会更好,但似乎已经有一种方法可以做到这一点,而且糟糕的 Ratchet 文档没有很好地概述它。
  • 一旦你说多个“应用程序”就意味着你在谈论应用层。它是在像 apache 这样的 http 服务器中拥有多个模块的同义词。您需要一些 ID(如您所述)来区分对不同应用程序的请求。在 HTTP 服务器的情况下,这是通过 URL 完成的。如果 Rachet 文档没有很好地记录它,那么可以在 Rachet 提供的连接之上实现自己的协议。
  • 您不一定需要转至 JSON。请记住,Websocket 连接也以常规 HTTP 连接开始。所以你可以使用 URL 来区分。您必须在文档中找到获取用于 websocket 握手的 URL 的方法。那就是如果 Rachet 允许访问它。
  • 找到它,您可以使用$querystring = $conn->WebSocket->request->getQuery(); 访问客户端发送的URL 这个查询字符串现在可以用来调用适当的处理程序。我假设您的客户端将连接到不同的 URL,例如 localhost:5050/app1 和 localhost:5050/app2
  • 感谢您提供详细信息。如果我没记错的话,您可以通过 Ratchet 路由器获得的查询仅适用于客户端和服务器之间的 websocket 连接(因为 $conn 对象仅在 Ratchet 应用程序中可用)。我想做的是在调用任何 Ratchet 应用程序之前区分路线。因此,对我来说,使用 ZMQ 在 apache 和棘轮 websocket 服务器之间建立一个简单的 tcp 连接可能是不可能的。
猜你喜欢
  • 1970-01-01
  • 2023-03-15
  • 2021-08-30
  • 1970-01-01
  • 2015-08-25
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 2023-03-07
相关资源
最近更新 更多