php - WebSockets - 通过 php 发送 json 数据

标签 php amazon-web-services websocket aws-api-gateway

我正在尝试从 PHP 向我的 websocket aws api 网关发送即发即弃请求。

我设置了一个名为“sendmessage”的操作。

这是我正在使用的代码:

$protocol = "ssl";
$host = "<myendpoint>.amazonaws.com";
$port = 443;
$path = "/<mystage>/";
$timeout = 2000;

$socket = pfsockopen($protocol . "://" . $host, $port,
                    $errno, $errstr, $timeout);

$content = "{'action': 'sendmessage', 'data': 'test'}";
$body = "POST $path HTTP/1.1\r\n";
$body .= "Host: $host\r\n";
$body .= "Content-Type: application/json\r\n";
$body .= "Content-Length: " . strlen($content) . "\r\n";
$body .= "Connection: Close\r\n\r\n";
$body .= $content;
$body .= "\r\n";

fwrite($socket, $body);

但是,什么也没发生。

如果我使用 wscat,例如:

wscat -c wss://<my-endpoint>.amazonaws.com/<my-stage>

> {'action': 'sendmessage', 'data': 'test'}
>

效果很好。

我的 php 代码做错了什么?

注意:我需要套接字连接是持久的(就像使用 pfsockopen 函数时的方式)。

最佳答案

由于您没有提供指针链接,因此根据自己的测试,这里有一些注释!

我猜问题出在wss部分,php需要先检索证书,这样才能加密数据。

您的代码应该在 ws:// 流上正常工作。

要连接到常规 ws:// 流,只需使用 fsockopen() .

<?php
$fp = fsockopen("udp://echo.websocket.org", 13, $errno, $errstr);
if (!$fp) {
    echo "ERROR: $errno - $errstr<br />\n";
} else {
    fwrite($fp, "\n");
    echo "Connected!";
    echo fread($fp, 26);
    fclose($fp);
}
<小时/>

但是要使用 php 连接到 wss:// 安全 websocket 流,无需使用库,我们需要首先通过查询 创建一个隧道公钥 stream_socket_client .

这是一种握手机制。这可以按如下方式完成。

注意第一个 ssl:// 调用。这是TLS 1.0协议(protocol)。

<?php  
$sock = stream_socket_client("ssl://echo.websocket.org:443",$e,$n,30,STREAM_CLIENT_CONNECT,stream_context_create(null));
if(!$sock){
 echo"[$n]$e".PHP_EOL;
} else {
  fwrite($sock,"GET / HTTP/1.1\r\nHost: echo.websocket.org\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(fgets($sock,2048));
  }
}

输出应如下所示:

string(44) "HTTP/1.1 101 Web Socket Protocol Handshake"
string(21) "Connection: Upgrade"
string(37) "Date: Thu, 12 Dec 2019 04:06:27 GMT"
string(52) "Sec-WebSocket-Accept: fTYwcEa6D9kJBtghptkz1e9CtBI="
string(25) "Server: Kaazing Gateway"
string(20) "Upgrade: websocket"
<小时/>

相同的基本代码,另一个示例,从 Binance wss:// 流中提取数据。

我们还可以使用TLS 1.2 ,用 tls:// 握手代替。适用于大多数服务器。

<?php
$sock = stream_socket_client("tls://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)));
  }
} 
<小时/>

这是一种从 php仅检索远程handpoint 的 ssl RSA 公钥的方法。可用于加快以后的连接速度。

<?php
$opt = [
  "capture_peer_cert" => true,
  "capture_peer_cert_chain" => true
];
$a = stream_context_create(["ssl"=>$opt]);
$b = stream_socket_client("ssl://stream.binance.com:9443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $a);
$cont = stream_context_get_params($b);
$key = openssl_pkey_get_public($cont["options"]["ssl"]["peer_certificate"]);
$c = openssl_pkey_get_details($key);
var_dump($c["key"]);

输出类似:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhki(...)7aEsFtUNkwM5R5b1mpqzAwqHyvdamJx20bT6SS6
PYXSr/dv8ak1d4e2Q0nIa1O7l3w0bZZ4wnp5B8Z+tjPd1W8uaZoRO2iVkPMh2yPl
j0mmtUw1YlfDyutH/t4FlRCDiD4JjdREQGs381/+jbkdjl2SIb1IyNiCdAXA6zsq
xwIDAQAB
-----END PUBLIC KEY-----

可能还有其他怪癖,当然,我们需要主要的指导点^。很高兴对此进行测试。否则祝你好运,关于这个主题的文档非常缺乏。

这是still a new born protocol (2011 年!)。最佳详细信息位于 RFC 规范中:

The WebSocket protocol was standardized by the IETF as RFC 6455 in 2011

关于握手,必须由GET请求发起。

The client will send a pretty standard HTTP request with headers that looks like this (the HTTP version must be 1.1 or greater, and the method must be GET)

Writing_WebSocket_servers#Client_handshake_request

<小时/>

简而言之:

If unencrypted WebSocket traffic flows through an explicit or a transparent proxy server without WebSockets support, the connection will likely fail.

WebSocket#Proxy_traversal

Transport_Layer_Security#Digital_certificates

关于php - WebSockets - 通过 php 发送 json 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59181730/

相关文章:

php 将值与存储在表中的用户定义的公式进行匹配并执行请求的数学运算

amazon-web-services - 带有预签名URL的S3 PUT请求拒绝访问

websocket - Cap'n Proto 中如何区分多种消息类型?

ruby-on-rails - 到 'ws://example.com/cable' 的 WebSocket 连接失败 : Unexpected response code: 404

amazon-web-services - SAM CLI 的自定义构建步骤

iphone - 具有完整规范支持的 Objective-C/C websocket 客户端

php - 使用php访问远程数据库

php - 如何计算PHP中的对角线差?

java - 如何检查 MySQL 表是否有来自 Java/Android 的下一行

amazon-web-services - 错误 !!! CloudFormation 模板验证