2014-03-13 219 views
6

我試圖將基於PHP的客戶端連接到websocket服務器。使用PHP客戶端連接到websocket

這是我一直在使用的代碼,已在不同論壇上廣泛發佈。但由於某種原因,我無法讓它工作。

任何幫助,將不勝感激。

$host = 'host'; //where is the websocket server 
$port = 443; //ssl 
$local = "http://www.example.com/"; //url where this script run 
$data = '{"id": 2,"command": "server_info"}'; //data to be send 

$head =  "GET/HTTP/1.1"."\r\n". 
       "Upgrade: WebSocket"."\r\n". 
       "Connection: Upgrade"."\r\n". 
       "Origin: $local"."\r\n". 
       "Host: $host"."\r\n". 
       "Content-Length: ".strlen($data)."\r\n"."\r\n"; 
////WebSocket handshake 
$sock = fsockopen($host, $port, $errno, $errstr, 2); 
fwrite($sock, $head) or die('error:'.$errno.':'.$errstr); 
$headers = fread($sock, 2000); 
fwrite($sock, "\x00$data\xff") or die('error:'.$errno.':'.$errstr); 
$wsdata = fread($sock, 2000); //receives the data included in the websocket package "\x00DATA\xff" 
$retdata = trim($wsdata,"\x00\xff"); //extracts data 
////WebSocket handshake 
fclose($sock); 

echo $retdata; 
+0

請出示你如何嘗試連接 – Shin

回答

8

我可能會更喜歡使用現有的WebSocket客戶端庫(也許https://github.com/gabrielbull/php-websocket-clienthttps://github.com/Devristo/phpws/tree/master/src/Devristo/Phpws/Client?),而不是推出自己的,但我得到了它的使用至少連接:

$head = "GET/HTTP/1.1"."\r\n". 
    "Host: $host"."\r\n". 
    "Upgrade: websocket"."\r\n". 
    "Connection: Upgrade"."\r\n". 
    "Sec-WebSocket-Key: asdasdaas76da7sd6asd6as7d"."\r\n". 
    "Sec-WebSocket-Version: 13"."\r\n". 
    "Content-Length: ".strlen($data)."\r\n"."\r\n"; 

我服務器使用TLS/SSL,所以我還需要:

$sock = fsockopen('tls://'.$host, $port, $errno, $errstr, 2); 

完整的協議規範爲:https://tools.ietf.org/rfc/rfc6455.txt

+3

這種反應讓我在正確的方向開始。稍微搜索一些其他論壇並調整頭文件代碼,我發現了以下解決方案。 https://ripple.com/forum/viewtopic.php?f=2&t=6171&p=43313#p43313我可以證實它的工作原理! –

+0

謝謝約翰您提供的鏈接工作 – Mancy

+2

鏈接已損壞= \ – Jonathan

4

你的標題必須包含:

Sec-WebSocket-Key: (some value) 
Sec-WebSocket-Version: 13 

連接成功。
進行連接時,還需要使用hybi10幀編碼。
參見:https://tools.ietf.org/rfc/rfc6455.txt - 雖然有點幹。

我做這個工作的例子:

<?php 
$sp=websocket_open('127.0.0.1/ws_request.php?param=php_test',$errstr); 
websocket_write($sp,"Websocket request message"); 
echo websocket_read($sp,true); 

$sp=websocket_open('127.0.0.1:8080/ws_request.php?param=php_test',$errstr); 
websocket_write($sp,"Websocket request message"); 
echo websocket_read($sp,true); 

function websocket_open($url){ 
    $key=base64_encode(uniqid()); 
    $query=parse_url($url); 
    $header="GET/HTTP/1.1\r\n" 
    ."pragma: no-cache\r\n" 
    ."cache-control: no-cache\r\n" 
    ."Upgrade: WebSocket\r\n" 
    ."Connection: Upgrade\r\n" 
    ."Sec-WebSocket-Key: $key\r\n" 
    ."Sec-WebSocket-Version: 13\r\n" 
    ."\r\n"; 
    $sp=fsockopen($query['host'],$query['port'], $errno, $errstr,1); 
    if(!$sp) die("Unable to connect to server ".$url); 
    // Ask for connection upgrade to websocket 
    fwrite($sp,$header); 
    stream_set_timeout($sp,5); 
    $reaponse_header=fread($sp, 1024); 
    if(!strpos($reaponse_header," 101 ") 
     || !strpos($reaponse_header,'Sec-WebSocket-Accept: ')){ 
    die("Server did not accept to upgrade connection to websocket" 
     .$reaponse_header); 
    }  
    return $sp; 
} 

function websocket_write($sp, $data,$final=true){ 
    // Assamble header: FINal 0x80 | Opcode 0x02 
    $header=chr(($final?0x80:0) | 0x02); // 0x02 binary 

    // Mask 0x80 | payload length (0-125) 
    if(strlen($data)<126) $header.=chr(0x80 | strlen($data)); 
    elseif (strlen($data)<0xFFFF) $header.=chr(0x80 | 126) . pack("n",strlen($data)); 
    elseif(PHP_INT_SIZE>4) // 64 bit 
    $header.=chr(0x80 | 127) . pack("Q",strlen($data)); 
    else // 32 bit (pack Q dosen't work) 
    $header.=chr(0x80 | 127) . pack("N",0) . pack("N",strlen($data)); 

    // Add mask 
    $mask=pack("N",rand(1,0x7FFFFFFF));  
    $header.=$mask; 

    // Mask application data. 
    for($i = 0; $i < strlen($data); $i++) 
    $data[$i]=chr(ord($data[$i])^ord($mask[$i % 4])); 

    return fwrite($sp,$header.$data);  
} 

function websocket_read($sp,$wait_for_end=true,&$err=''){ 
    $out_buffer=""; 
    do{ 
    // Read header 
    $header=fread($sp,2); 
    if(!$header) die("Reading header from websocket failed"); 
    $opcode = ord($header[0]) & 0x0F; 
    $final = ord($header[0]) & 0x80; 
    $masked = ord($header[1]) & 0x80; 
    $payload_len = ord($header[1]) & 0x7F; 

    // Get payload length extensions 
    $ext_len = 0; 
    if($payload_len >= 0x7E){ 
     $ext_len = 2; 
     if($payload_len == 0x7F) $ext_len = 8; 
     $ext=fread($sp,$ext_len); 
     if(!$ext) die("Reading header extension from websocket failed"); 

     // Set extented paylod length 
     $payload_len= 0; 
     for($i=0;$i<$ext_len;$i++) 
     $payload_len += ord($header[$i]) << ($ext_len-$i-1)*8; 
    } 

    // Get Mask key 
    if($masked){ 
     $mask=fread($sp,4); 
     if(!$mask) die("Reading header mask from websocket failed"); 
    } 

    // Get payload 
    $frame_data=''; 
    do{ 
     $frame= fread($sp,$payload_len); 
     if(!$frame) die("Reading from websocket failed."); 
     $payload_len -= strlen($frame); 
     $frame_data.=$frame; 
    }while($payload_len>0);  

    // if opcode ping, reuse headers to send a pong and continue to read 
    if($opcode==9){ 
     // Assamble header: FINal 0x80 | Opcode 0x02 
     $header[0]=chr(($final?0x80:0) | 0x0A); // 0x0A Pong 
     fwrite($sp,$header.$ext.$mask.$frame_data); 

    // Recieve and unmask data 
    }elseif($opcode<3){ 
     $data=""; 
     if($masked) 
     for ($i = 0; $i < $data_len; $i++) 
      $data.= $frame_data[$i]^$mask[$i % 4]; 
     else  
     $data.= $frame_data; 
     $out_buffer.=$data; 
    } 

    // wait for Final 
    }while($wait_for_end && !$final); 

    return $out_buffer; 
} 

你可以得到完整的版本在這裏:https://github.com/paragi/PHP-websocket-client

+1

「事件服務器不接受將連接升級到websocket。」該怎麼辦 ? – pinkvoid

+1

這取決於您的設置和來自服務器的響應。你可以打印出$ reaponse_header,看看我是否給出了一個線索。 您的web服務器是否支持您使用的端口上的websockets? –

+0

我有一個問題,它不能連接以及不知道爲什麼。我正在使用來自github的最新代碼。 –

相關問題