使用 PHP 客户端连接到 websocket
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22370966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Connecting to websocket with PHP client
提问by John Whelan
I'm trying to connect a PHP-based client to a websocket server.
我正在尝试将基于 PHP 的客户端连接到 websocket 服务器。
Here's the code I have been using which has been widely published on different forums. But for some reason I just cannot get it to work.
这是我一直在使用的代码,它已在不同的论坛上广泛发布。但由于某种原因,我无法让它发挥作用。
Any help would be appreciated.
任何帮助,将不胜感激。
$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;
回答by singpolyma
I would probably prefer to use an existing websocket client library (maybe https://github.com/gabrielbull/php-websocket-clientor https://github.com/Devristo/phpws/tree/master/src/Devristo/Phpws/Client?) rather than roll your own, but I got it to at least connect by using:
我可能更喜欢使用现有的 websocket 客户端库(可能是https://github.com/gabrielbull/php-websocket-client或https://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";
My server is using TLS/SSL, so I also needed:
我的服务器使用 TLS/SSL,所以我还需要:
$sock = fsockopen('tls://'.$host, $port, $errno, $errstr, 2);
The full protocol spec is: https://tools.ietf.org/rfc/rfc6455.txt
完整的协议规范是:https: //tools.ietf.org/rfc/rfc6455.txt
回答by Simon Rigét
UPDATE 2019: many servers requires the key to be more unique that the original example, resulting in failure to establish upgrade connection. The key generation is now changed accordingly.
UPDATE 2019:许多服务器要求密钥比原始示例更独特,导致无法建立升级连接。密钥生成现在相应地更改。
Your header must contain:
您的标题必须包含:
Sec-WebSocket-Key: (some value)
Sec-WebSocket-Version: 13
to connect successfully.
When you have made the connection, you also need to use the hybi10 frame encoding.
See: https://tools.ietf.org/rfc/rfc6455.txt- Its a bit dry though.
连接成功。
建立连接后,还需要使用 hybi10 帧编码。
请参阅:https: //tools.ietf.org/rfc/rfc6455.txt- 不过有点干。
I have made this working example:
我做了这个工作示例:
<?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(openssl_random_pseudo_bytes(16));
$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;
}
You can get the full version here: https://github.com/paragi/PHP-websocket-client
你可以在这里获得完整版本:https: //github.com/paragi/PHP-websocket-client
回答by NVRM
Connecting to a WSS streamwith purely php:
使用纯 php连接到WSS 流:
Example with the public binance wss api.
公共币安 wss api 的示例。
<?php
$sock = stream_socket_client("ssl://stream.binance.com:9443",$error,$errnum,30,STREAM_CLIENT_CONNECT,stream_context_create(null));
if (!$sock) {
echo "[$errnum] $error" . PHP_EOL;
} else {
echo "Connected - Do NOT get rekt!" . PHP_EOL;
fwrite($sock, "GET /stream?streams=btcusdt@kline_1m HTTP/1.1\r\nHost: stream.binance.com:9443\r\nAccept: */*\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: ".rand(0,999)."\r\n\r\n");
while (!feof($sock)) {
var_dump(explode(",",fgets($sock, 512)));
}
}
More details: WebSockets - send json data via php
回答by pedro casas
The 400 error is because you're missing Hostand Originin the header.
400 错误是因为您在标题中缺少Host和Origin。
$key=base64_encode(openssl_random_pseudo_bytes(16));
$query=parse_url($url);
$local = "http://".$query['host'];
if (isset($_SERVER['REMOTE_ADDR'])) $local = "http://".$_SERVER['REMOTE_ADDR'];
$header="GET / HTTP/1.1\r\n"
."Host: ".$query['host']."\r\n"
."Origin: ".$local."\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";
回答by Mayank Tiwari
https://github.com/ratchetphp/Pawl
https://github.com/ratchetphp/Pawl
I tried around 10 different solutions from various stackoverflow threads but nothing worked, after spending about 6 hours trying different solution this worked for me. scenario: Ratchet as server I was able to connect via reactjs I wasn't able to connect via php, Expected Result: To send message from php-client to all connected react clients. the git repo i provided was a lucky break i was looking for.
我尝试了来自各种 stackoverflow 线程的大约 10 种不同的解决方案,但没有任何效果,在花了大约 6 个小时尝试不同的解决方案后,这对我有用。场景:Ratchet 作为服务器我能够通过 reactjs 连接我无法通过 php 连接,预期结果:从 php-client 向所有连接的 react 客户端发送消息。我提供的 git repo 是我一直在寻找的幸运突破。

