2013-06-05 146 views
1

使用socketo.me網站上的說明,我試圖讓使用棘輪for php的websockets工作。根據說明,我需要在我的composer.json文件中使用棘輪版本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的結果幾乎一樣。棘輪Websockets立即關閉

這是我的類,實現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'); 
} 

這是我在我的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「handshake」的不兼容版本可能會導致這種情況發生,但我從來沒有發現任何關於其他版本的Ratchet的信息,或者我需要做什麼才能讓兼容版本在客戶端上運行,服務器。我還發現一些評論說有時候onopen根本不會被打電話,我覺得很難相信。任何想法可能是什麼問題或如何解決它將不勝感激。

+0

看起來您的客戶端在從服務器收到消息時會斷開連接,這發生在onMessage(),所以當服務器收到來自客戶端的消息時。你能發佈發送消息到服務器的客戶端代碼嗎? – mattexx

+0

我實際上沒有足夠的把任何數據發送到服務器。但是,當我添加'conn.send'(從客戶端發送消息)'';在客戶端JavaScript中,我從Chrome的JavaScript控制檯收到以下消息: WebSocket {binaryType:「blob」,extensions:「 「,protocol:」「,onclose:null,onerror:null ...} 未捕獲錯誤:InvalidStateError:DOM異常11 已關閉 – user2455811

+0

服務器認爲它正在收到消息,否則它不會觸發onMessage()。你只是在你的html中調用test_websockets()來產生上面的shell腳本輸出? – mattexx

回答

4

使用

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

,而不是

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

如果按照棘輪的文檔和RFC6455正確,那麼你會發現,當一個WebSocket連接請求時,具體的迴應將被髮送到客戶端。除非收到回覆,否則客戶會認爲連接沒有完成。

您的情況的問題是正在處理連接的MessageComponentInterface沒有響應連接上的任何套接字響應。然而,棘輪捆綁了一個名爲WsServer的已經實現的類,你的聊天類的對象可以傳遞給它,並且可以實現所需的操作。但是WsServer並不是MessageComponentInterface,但是如果你把它包裝在HttpServer裏面,幸運的是它也與棘輪捆綁在一起,你的問題就會解決。

因此新的代碼如下:

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

Ofcourse,你將需要添加WsServer和HttpServer的命名空間中。