2

I'm currently working on a PHP application that will be using some websocket connections to talk to another service.

To talk to this websocket service, we are using Ratchet - which is a PHP library based on react PHP.

This piece of code needs to send and respond to a couple of requests, and after that, should return the information to the "main thread".

Example flow:

HTTP request -> controller -> Starts a service which opens a websocket client -> websocket client is talking to server -> once its done it should return the outcome to the controller code -> controller outputs to user

The issue I'm having is that I'm not familiar with Reactive PHP and am not sure how to handle this.

I've tried;

    $service = new WebsocketService();
    $startTimer = time();
    $service->getList(44);
    while($service->getResponse() == null) {
        usleep(500);
        if (time() > $startTimer + 10) {
            continue; //Timeout on 10 seconds
        }
    }
    var_dump($service->getResponse());

The service code would set its "response" variable to something other than null once its done. This obviously fails, because the sleep method is blocking the thread. Also without, it seems like the while loop is blocking I/O and the reactive code fails.

A solution would be to open up a new thread and run the websocket code there, but I wouldn't be happy with that.

I feel like I need to implement some sort of "watcher" around the websocket process, but I'm not sure how to do that.

Our Websocket service client code looks like this;

private $response = null;

/**
 * @return null|object
 */
public function getResponse() {
    return $this->response;
}

public function getList($accountId) {
    $this->response = null;
    \Ratchet\Client\connect('ws://192.168.56.1:8080')->then(function(\Ratchet\Client\WebSocket $conn) use ($accountId) {
        $login = new \stdClass();
        $login->action = 'login';
        $conn->on('message', function($msg) use ($conn, $login, $accountId) {
            try {
                $response = json_decode($msg);
                if ($response->result_id == 100) {
                    //Succesfully logged in to websocket server

                    //Do our request now.
                    $message = new \stdClass();
                    $message->target = 'test';
                    $conn->send(json_encode($message));
                }

                if (isset($response->reply) && $response->reply == 'list') {
                    $this->response = $response; //This is the content I need returned in the controller
                    $conn->close(); //Dont need it anymore
                }

            } catch (\Exception $e) {
                echo 'response exception!';
                //Do nothing for now
            }
        });

        $conn->send(json_encode($login));
    }, function ($e) {
        echo "Could not connect: {$e->getMessage()}\n";
    });
}

Running the code like this also does not work;

    $service = new WebsocketService();
    $service->getList(44);
    echo 'Test';
    var_dump($service->getResponse());

because the "test" echo comes before I even get a response from the websocket server.

Please, enlighten me! I'm not sure what to search for.

4

2 回答 2

1

PHP 和 websockets 似乎仍然有点实验性。不过,我在 medium.com 上找到了一个很棒的教程,由 Adam Winnipass 编写,它应该对解决您的问题非常有帮助:https ://medium.com/@winni4eva/php-websockets-with-ratchet-5e76bacd7548

唯一的区别是他们使用 JavaScript 而不是 PHP 来实现他们的 websocket 客户端。但最终应该不会有太大区别,因为一旦我们打开了每一端的 Websocket 连接,两个应用程序都必须发送并等待接收通知 - 这就是他们说明它的方式:

建立 Web Socket 连接

似乎创建成功的 Websocket 连接的一种可能性是扩展 MessageComponentInterface

use Ratchet\MessageComponentInterface;

这也需要

use Ratchet\ConnectionInterface;

消息组件接口定义了以下方法:

  • 打开
  • onMessage
  • 关闭
  • 错误

我认为这就是 Ratchet 库的实现方式。这就是他们最终启动服务器的方式:

use Ratchet\Server\IoServer;
use MyApp\MyCustomMessageComponentInterface;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
            new HttpServer(
                new WsServer(
                    new MyCustomMessageComponentInterface()
                )
            ),
          8080
         );
$server->run();

使用这种架构,您已经可以接收 (onMessage) 并且使用 send() 方法也可以发送。

我无法用您现有的代码解决确切的问题。但我想如果您按预期使用库的预构建类和接口 (并在此处演示),您应该能够通过将代码添加到相应的方法来实现您想要的。

更多信息和示例可以在文档中找到:

http://socketo.me/docs/server

http://socketo.me/api/namespace-Ratchet.html

于 2019-06-25T16:45:59.590 回答
-1

您是否使用 WsServer 扩展类,如果您遇到致命错误,这可能是个问题。我不确定您是否收到致命错误或警告。我还注意到公共函数 onOpen() 打开了一个连接。请尝试参考此文档http://socketo.me/api/class-Ratchet.WebSocket.WsServer.html可能有用。

于 2017-03-31T00:12:15.123 回答