Веб-сокеты с Ratchet закрываются немедленно

Используя указания на сайте socketo.me, я пытаюсь заставить веб-сокеты работать с помощью Ratchet для php. . В соответствии с инструкциями мне потребовалась Ratchet версии 0.2.* в моем файле composer.json. Я использую php 5.4.9-4ubuntu2 и Apache 2. Для браузеров я использую Firefox 21.0 и Chrome 26.0.1410.63. На на этом сайте говорится, что Rachet поддерживает Firefox 6–20 и Chrome 13–26, но при использовании Firefox результаты почти идентичны. 21, как в Chrome 26.

Вот мой класс, реализующий MessageComponentInterface.

<?php
namespace WebsocketTest;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

require dirname (__DIR__).'/../../../../vendor/autoload.php';

class Chat implements MessageComponentInterface
{
    protected $clients;

    public function __construct ()
    {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen (ConnectionInterface $conn)
    {
        // Store the new connection to send messages to later
        $this->clients->attach ($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 $client)
        {
            if ($from !== $client)
            {
                // The sender is not the receiver, send to each client connected
                $client->send ($msg);
            }
        }
    }

    public function onClose (ConnectionInterface $conn)
    {
        // The connection is closed, remove it, as we can no longer send it messages
        $this->clients->detach ($conn);
        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError (ConnectionInterface $conn, \Exception $e)
    {
        echo "An error has occurred: {$e->getMessage()}\n";
        $conn->close ();
    }
}

Вот мой код сценария оболочки.

<?php
use Ratchet\Server\IoServer;
use WebsocketTest\Chat as Chat;

require_once __DIR__.'/Chat.php';

$server = IoServer::factory (new Chat (), 8080);
$server->run ();

Вот вывод, который я получаю из сценария оболочки.

New connection! (38)
Connection 38 sending message "GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: www.zf2.dev:8080
Origin: http://www.zf2.dev
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: YHbsxEgVhWTDJjaBJAGHdQ==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame

" to 1 other connection
New connection! (39)
Connection 39 sending message "GET / HTTP/1.1
Host: www.zf2.dev:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://www.zf2.dev
Sec-WebSocket-Key: EPpLFS3bXx/eC+WaoNDacA==
Connection: keep-alive, Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

" to 2 other connections
Connection 37 has disconnected
Connection 38 has disconnected

Вот мой код javascript. После создания соединения я вывожу его в консоль javascript.

var conn = null;
function test_websockets ()
{
    conn = new WebSocket ('ws://www.zf2.dev:8080');
    console.log (conn);
    conn.onopen = function (e) { console.log ("Connection established!"); };
    conn.onmessage = function (e) { console.log (e.data); };
    conn.onclose = function (e) { console.log ('closed') };
//  conn.send ('sending message from the client');
}

function test_ws_message ()
{
    conn.send ('the test message');
}

Это вывод, который я получаю в своей консоли javascript в Chrome.

WebSocket {binaryType: "blob", extensions: "", protocol: "", onclose: null, onerror: null…}
 html5test.js:34
Uncaught Error: InvalidStateError: DOM Exception 11 html5test.js:47
test_ws_message html5test.js:47
onclick

И это вывод, который я получаю от Firebug в Firefox.

WebSocket { url="ws://www.zf2.dev:8080", readyState=0, bufferedAmount=0, more...}
html5test.js (line 34)
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
[Break On This Error]   

conn.send ('the test message');

html5test.js (line 47)
closed
html5test.js (line 38)
Firefox can't establish a connection to the server at ws://www.zf2.dev:8080/.


conn = new WebSocket ('ws://www.zf2.dev:8080');

Обратите внимание, что Firefox показывает, что соединение немедленно закрыто, а Chrome — нет. Однако Chrome никогда не показывает, что соединение открыто, поэтому я не думаю, что оно работает ни в одном из браузеров. Похоже, серверный скрипт считает, что соединения были установлены, но ни один из браузеров никогда не показывает мне "Соединение установлено!" сообщение, указывающее, что был вызван метод onopen. Мне удалось найти один комментарий, в котором говорилось, что несовместимые версии «рукопожатия» веб-сокетов могут вызвать это, но я так и не нашел никакой информации о другой версии Ratchet или о том, что мне нужно сделать, чтобы запустить совместимую версию на клиенте и сервер. Я также нашел некоторые комментарии, в которых говорилось, что иногда onopen вообще не вызывается, во что мне трудно поверить. Любые идеи о том, в чем может быть проблема или как ее исправить, будут очень признательны.


person user2455811    schedule 05.06.2013    source источник
comment
Похоже, ваши клиенты отключаются, когда получают сообщение от сервера, что происходит в onMessage(), поэтому, когда сервер получает сообщение от клиента. Можете ли вы опубликовать клиентский код, который отправляет сообщение на сервер?   -  person mattexx    schedule 05.06.2013
comment
На самом деле я не продвинулся достаточно далеко, чтобы отправить какие-либо данные на сервер. Но когда я добавляю строку conn.send ('sending message from the client'); в javascript на стороне клиента, я получаю следующие сообщения из консоли javascript Chrome: WebSocket {binaryType: blob, extensions:, protocol:, onclose: null, onerror: null…} Uncaught Error: InvalidStateError: Исключение DOM 11 закрыто   -  person user2455811    schedule 05.06.2013
comment
Что ж, сервер думает, что получил сообщение, иначе он не сработал бы onMessage(). Вы просто вызываете test_websockets() в своем html для создания вывода сценария оболочки выше?   -  person mattexx    schedule 05.06.2013
comment
Да, я вызываю test_websockets(). Я изменил его так, чтобы переменная conn была глобальной, но это не помогло, и я переместил вызов conn.send() в отдельную функцию javascript, которую я могу вызвать, щелкнув div в своем пользовательском интерфейсе. В приведенном выше выводе показано сообщение от OnMessage, потому что я изначально пытался вызвать команду send сразу после создания соединения. Но я прокомментировал вызов для отправки, чтобы посмотреть, могу ли я сначала просто создать соединение, но оно каждый раз закрывается. Firefox теперь сообщает мне InvalidStateError: была предпринята попытка использовать объект, который не является или более непригоден для использования.   -  person user2455811    schedule 05.06.2013
comment
Можете ли вы обновить свой вопрос, чтобы включить весь ваш последний код? Следить за изменениями кода через комментарии очень сложно.   -  person mattexx    schedule 05.06.2013
comment
Хорошо, я обновил свои примеры кода, чтобы отразить то, что у меня есть на данный момент, и результаты, которые я получаю на сервере и клиенте.   -  person user2455811    schedule 05.06.2013
comment
Веб-сокеты вашего браузера должны быть совместимы с Ratchet. Я подозреваю, что эта проблема является артефактом вашего тестирования. Вы устанавливаете несколько соединений с одной и той же консоли javascript? Если это так, попробуйте использовать отдельные вкладки или окна для каждого соединения.   -  person mattexx    schedule 06.06.2013
comment
Я думаю, что клиент пытается установить соединение, но сервер никогда не отвечает, и время ожидания клиента истекает. Потому что я вижу, что запрос отправляется в Firebug, но он никогда не возвращается, а затем соединение закрывается. Я думаю, вы можете быть правы, что мой клиент не совместим с Ratchet. Я только что настроил phpws и запустил демонстрационный сервер, и он сразу же подключился, и я смог отправить сообщение.   -  person user2455811    schedule 06.06.2013


Ответы (2)


Если вы правильно следуете документации Ratchet и RFC6455, то заметите, что при запросе на подключение к веб-сокету клиенту должен быть отправлен определенный ответ. Если ответ не получен, клиент будет считать, что соединение не установлено.

Проблема в вашем случае заключается в том, что MessageComponentInterface, обрабатывающий соединение, не отвечает ни одним ответом сокета при соединении. Однако Ratchet объединяется с уже реализованным классом с именем WsServer, которому можно передать объект вашего класса Chat и выполнить желаемую операцию. Однако WsServer не является MessageComponentInterface, но если вы оберните его внутри HttpServer, который, к счастью, также связан с Ratchet, ваша проблема будет решена.

Таким образом, ваш новый код будет выглядеть так:

$server = IoServer::factory (new HttpServer(new WsServer(new Chat ())), 8080);

Конечно, вам нужно будет добавить WsServer и HttpServer в пространство имен.

person Arun Poudel    schedule 10.11.2014

использовать

$server = IoServer::factory (new HttpServer(new WsServer(new Chat())), 8080);

вместо

$server = IoServer::factory (new Chat (), 8080);
person yellowsir    schedule 03.08.2013