使用socketo.me网站上的说明,我正在尝试使用Ratchet for php使websockets工作。根据说明,我在我的composer.json文件中需要Ratchet版本0.2。*。我正在使用php 5.4.9-4ubuntu2和Apache 2.对于浏览器我使用的是Firefox 21.0和Chrome 26.0.1410.63。 This site表示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 ();
}
}
这是我的shell脚本代码。
<?php
use Ratchet\Server\IoServer;
use WebsocketTest\Chat as Chat;
require_once __DIR__.'/Chat.php';
$server = IoServer::factory (new Chat (), 8080);
$server->run ();
以下是我从shell脚本获得的输出。
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');
}
这是我在Chrome浏览器的javascript控制台中获得的输出。
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
这是我在Firefox中从Firebug获得的输出。
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方法被调用。我能够找到一条评论,表明不兼容的websockets“握手”版本可能会导致这种情况发生,但我从未发现任何有关Ratchet其他版本的信息,或者我需要做些什么才能在客户端上运行兼容版本服务器。我还发现了一些评论,说有时候onopen根本没有被调用,我很难相信。关于问题可能是什么或如何解决问题的任何想法将不胜感激。
答案 0 :(得分:6)
如果您正确地遵循Ratchet的文档和RFC6455,那么您会注意到,当发出websocket连接请求时,将向客户端发送特定的响应。除非收到响应,否则客户端将认为尚未建立连接。
您的案例的问题是处理连接的MessageComponentInterface
没有响应连接上的任何套接字响应。但是,Ratchet捆绑了一个已经实现的类WsServer
,可以将Chat类的对象传递给它,并且可以实现所需的操作。但是WsServer不是MessageComponentInterface
,但如果你将它包装在HttpServer
里面,幸运的是它也与Ratchet捆绑在一起,你的问题就会解决。
所以你的新代码看起来像是:
$server = IoServer::factory (new HttpServer(new WsServer(new Chat ())), 8080);
当然,您需要在命名空间中添加WsServer和HttpServer。
答案 1 :(得分:4)
使用
$server = IoServer::factory (new HttpServer(new WsServer(new Chat())), 8080);
而不是
$server = IoServer::factory (new Chat (), 8080);