WebSockets - 通过 php 发送 json 数据

WebSockets - send json data via php(WebSockets - 通过 php 发送 json 数据)
本文介绍了WebSockets - 通过 php 发送 json 数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

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

我设置了一个名为sendmessage"的操作.

这是我正在使用的代码:

$protocol = "ssl";$host = ".amazonaws.com";$端口 = 443;$path = "//";$超时= 2000;$socket = pfsockopen($protocol . "://" . $host, $port,$errno, $errstr, $timeout);$content = "{'action': 'sendmessage', 'data': 'test'}";$body = "POST $path HTTP/1.1
";$body .= "主机:$host
";$body .= "内容类型:应用程序/json
";$body .= "内容长度:" .strlen($content) ."
";$body .= "连接:关闭

";$body .= $content;$body .= "
";fwrite($socket, $body);

然而,什么也没发生.

如果我使用 wscat,例如:

wscat -c wss://.amazonaws.com/>{'动作':'发送消息','数据':'测试'}>

效果很好.

我的 php 代码做错了什么?

注意:我需要保持套接字连接(使用 pfsockopen 函数时的方式).

解决方案

由于你没有提供handpoint链接,这里有一些注意事项,请自行测试!

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

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

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


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

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

注意第一个 ssl:// 调用.这是TLS 1.0 协议.

输出应如下所示:

string(44) HTTP/1.1 101 Web Socket 协议握手"string(21) 连接:升级"string(37) 日期:2019 年 12 月 12 日星期四 04:06:27 GMT"string(52) "Sec-WebSocket-Accept: fTYwcEa6D9kJBtghptkz1e9CtBI="string(25) 服务器:Kaazing 网关";string(20) 升级:websocket";


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

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


这是一种从 php 检索仅远程手持设备的 ssl RSA 公钥的方法.可用于加速以后的连接.

真的,capture_peer_cert_chain"=>真的];$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"]);

输出类似:

-----开始公钥--MIIBIjANBgkqhki(...)7aEsFtUNkwM5R5b1mpqzAwqHyvdamJx20bT6SS6PYXSr/dv8ak1d4e2Q0nIa1O7l3w0bZZ4wnp5B8Z+tjPd1W8uaZoRO2iVkPMh2yPlj0mmtUw1YlfDyutH/t4FlRCDiD4JjdREQGs381/+jbkdjl2SIb1IyNiCdAXA6zsqxwIDAQAB-----结束公钥-----

可能还有其他怪癖,当然,我们需要主要的handpoint^.很高兴测试一下.否则祝你好运,关于这个主题的文档非常缺乏.

这是仍然是一个新生的协议(2011 年!).最好的细节在 RFC 规范中:

<块引用>

WebSocket 协议由 IETF 标准化为 RFC 64552011

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

<块引用>

客户端将发送一个非常标准的 HTTP 请求,其标头为看起来像这样(HTTP 版本必须是 1.1 或更高版本,并且方法必须是GET)

Writing_WebSocket_servers#Client_handshake_request


简而言之:

<块引用>

如果未加密的 WebSocket 流量流经显式或不支持 WebSockets 的透明代理服务器,连接可能会失败.

WebSocket#Proxy_traversal

Transport_Layer_Security#Digital_certificates

I'm trying to send a fire-and-forget request from PHP to my websocket aws api gateway.

I've set up an action called "sendmessage".

This is the code I'm using:

$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
";
$body .= "Host: $host
";
$body .= "Content-Type: application/json
";
$body .= "Content-Length: " . strlen($content) . "
";
$body .= "Connection: Close

";
$body .= $content;
$body .= "
";

fwrite($socket, $body);

However, nothing happens.

If I use wscat, like:

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

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

it works just fine.

What am I doing wrong in my php code?

Note: I need the socket connection to be persistent (the way it is when using the pfsockopen function).

解决方案

Since you didn't provide a handpoint link, here is some notes, following own tests!

I guess the issue comes from the wss part, php needs to retrieve the certificate first, so it can encrypt the data.

Your code should work just fine on a ws:// stream.

To connect to a regular ws:// stream, one can simply use fsockopen().

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


But to connect to a wss:// secure websocket stream, using php, without libraries, we need to create a tunnel first, by querying the public key with stream_socket_client.

This is a handshake mechanism. This can be done as follow.

Notice the first ssl:// call. This is the 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
Host: echo.websocket.org
Accept: */*
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: ".rand(0,999)."

");
  while(!feof($sock)){
    var_dump(fgets($sock,2048));
  }
}

The output should looks like:

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"


Same base code, another example, pulling data from Binance wss:// stream.

We can also use TLS 1.2, with a tls:// handshake instead. Works on most servers.

<?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
Host: stream.binance.com:9443
Accept: */*
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: ".rand(0,999)."

");
  while (!feof($sock)) {
    var_dump(explode(",",fgets($sock, 512)));
  }
} 


Here is a way to retrieve only the ssl RSA public key of a remote handpoint, from php. Can be used to speed up later connections.

<?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"]);

Output something like:

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

There is possibly other quircks, to be sure, we need the main handpoint^. Would be glad to test that. Otherwise good luck, there is a big lack of documentation on the subject.

This is still a new born protocol (2011!). Best details are in the RFC specification:

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

About the handshake, it must be initiated by a GET request.

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


In short:

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

这篇关于WebSockets - 通过 php 发送 json 数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

DeepL的翻译效果还是很强大的,如果我们要用php实现DeepL翻译调用,该怎么办呢?以下是代码示例,希望能够帮到需要的朋友。 在这里需要注意,这个DeepL的账户和api申请比较难,不支持中国大陆申请,需要拥有香港或者海外信用卡才行,没账号的话,目前某宝可以
PHP通过phpspreadsheet导入Excel日期,导入系统后,全部变为了4开头的几位数字,这是为什么呢?原因很简单,将Excel的时间设置问文本,我们就能看到该日期本来的数值,上图对应的数值为: 要怎么解决呢?进行数据转换就行,这里可以封装方法,或者用第三方的
mediatemple - can#39;t send email using codeigniter(mediatemple - 无法使用 codeigniter 发送电子邮件)
Laravel Gmail Configuration Error(Laravel Gmail 配置错误)
Problem with using PHPMailer for SMTP(将 PHPMailer 用于 SMTP 的问题)
Issue on how to setup SMTP using PHPMailer in GoDaddy server(关于如何在 GoDaddy 服务器中使用 PHPMailer 设置 SMTP 的问题)