从PHP脚本发送消息到多个Ratchet Websocket应用程序(通过ZMQ Socket)

Eri*_*oom 6 php zeromq phpwebsocket ratchet

所以,我正在运行一个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('*'));
Run Code Online (Sandbox Code Playgroud)

从这里我绑定一个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 Code Online (Sandbox Code Playgroud)

最后,服务器启动:

//run
$loop->run();
Run Code Online (Sandbox Code Playgroud)

只要我只将棘轮应用程序中的一个绑定到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'));
Run Code Online (Sandbox Code Playgroud)

$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'));
Run Code Online (Sandbox Code Playgroud)

但是,当绑定第二个套接字时,这会导致ZMQ发出错误消息,称给定的地址已被使用.

所以问题是,是否还有其他方法可以在ZMQ套接字上使用路由?或者我应该使用其他方法来区分单独的Ratchet应用程序的消息,如果是,那么什么是一个好的解决方案?我想绑定到两个不同的端口,但想到这将是一个非常难看的解决方案?!

Aja*_*iya 2

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

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

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

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

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

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

可以使用以下方式获取请求 URL

$querystring = $conn->WebSocket->request->getQuery();
Run Code Online (Sandbox Code Playgroud)

现在客户端可以使用连接

ws://localhost:5050/app1 
and
ws://localhost:5050/app2
Run Code Online (Sandbox Code Playgroud)

您的不同应用程序现在可以单独处理这些连接。