螺旋桨WebSocket服务器能否向客户端自己发送消息?

19
我想使用 Ratchet (http://socketo.me) 来实现 iPhone 应用和服务器之间的永久连接,并需要在应用和服务器之间交换数据。
从这个例子 (http://socketo.me/docs/hello-world) 中,我发现有一个名为 onMessage 的函数,当应用程序向服务器发送消息时,将调用该函数,服务器可以向应用程序发送响应。
但服务器还必须能够在不从应用程序获取数据的情况下向应用程序发送数据。例如,应用程序与服务器之间建立了连接。服务器上发生了什么,我们需要向应用程序发送新数据。我怎样做以及是否可能?
主要问题是如何从服务器向应用程序发送数据?
感谢任何帮助。
3个回答

13

确实是有可能的。您需要以某种方式与WebSocket服务器进程通信。您可以使用某种形式的消息传递,无论是RPC还是消息队列。

Ratchet本身基于React事件循环。这意味着任何与Ratchet的通信形式都必须与该事件循环集成。在React主页上,您可以看到已经存在的一些集成:

在Ratchet文档中,有一篇关于如何使用React/ZMQ将消息从任何地方推送到WebSocket服务器的教程。


1
React/ZMQ的好例子。但我找不到如何将正确的数据(例如,我创建的特殊JSON)推送给正确的用户。例如,我必须向正确的用户发送数据(我有用户ID列表)。这是否需要用户已经订阅了“特定页面”(就像他们在这里说的那样:http://socketo.me/docs/push)? - lexa
igorw,我们能否通过某种方式(例如Skype)直接联系您以提出问题?非常感谢您的帮助。 - lexa
在irc.freenode.net上有一个#reactphp IRC频道。 - igorw

7

Ratchet还实现了WAMP,其中包括PubSub。因此,您的客户端可以订阅某些主题,而您可以有其他客户端(例如在后端基础设施上运行)发布到这些主题。例如,您可以使用基于AutobahnPython的客户端通过Ratchet发布到基于AutobahnAndroid的移动应用程序或基于AutobahnJS的HTML5客户端。


它使用wampv1,而iOS没有v1的库。是否有一种使用MessageComponent接口进行推送的方法? - harveyslash
Thruway支持WAMPv2 https://github.com/voryx/Thruway,因此您应该能够与https://github.com/mogui/MDWamp一起使用。 - oberstet

0

我曾经有同样的问题,这是我的解决方法。

基于hello world教程,我用数组替换了SplObjectStorage。在展示我的修改之前,我想说如果你已经按照那个教程并理解了它,那么阻止你自己找到这个解决方案的唯一原因可能就是不知道SplObjectStorage是什么。

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();
    }
}

当然,为了使其真正有用,您可能还需要添加一个数据库连接,并存储/检索这些资源ID。


3
非常好用!但它的工作方式类似于ack,一旦服务器收到消息,你就可以向客户端发送消息。那么我如何在不从客户端接收消息的情况下发送(启动)消息到客户端? - indianwebdevil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接