[英]WebSocket handshake declined by remote peer
所以我一直在尝试遵循 ssl websocket 连接到 binance 的提升代码,但在尝试启动握手时我一直收到错误消息。 我已经删除了 load_root_certificates function 顺便说一句,因为它说 function 是未定义的,我看到一个帖子说你不需要,因为它会在我的机器中加载默认证书。 不确定最后一个陈述是否属实。
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/beast/core/ostream.hpp>
#include <string>
#include <utility>
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <iostream>
#include "JSONParser.hpp"
#include "data.hpp"
#define ONEHOUR_ONEMONTH 672
#define ONEMIN_ONEWEEK 10080
#define ONESEC_ONEDAY 86400
std::string create_subscription_message() {
boost::property_tree::ptree message;
message.put("method", "SUBSCRIBE");
std::vector<std::string> streams = {"btcusdt@kline_1m"};
boost::property_tree::ptree params;
for(auto& stream: streams)
params.push_back(std::make_pair("", boost::property_tree::ptree(stream)));
message.add_child("params", params);
message.put("id", 1);
std::stringstream ss;
boost::property_tree::write_json(ss, message);
return ss.str();
}
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
using tcp = boost::asio::ip::tcp;
int main() {
try {
cData candlesticks(ONEMIN_ONEWEEK);
std::string s = "{\n \"e\": \"kline\",\n \"E\": 123456789,\n \"s\": \"BNBBTC\",\n \"k\": {\n \"t\": 123400000,\n \"T\": 123460000,\n \"s\": \"BNBBTC\",\n \"i\": \"1m\",\n \"f\": 100,\n \"L\": 200,\n \"o\": \"0.0010\",\n \"c\": \"0.0020\",\n \"h\": \"0.0025\",\n \"l\": \"0.0015\",\n \"v\": \"1000\",\n \"n\": 100,\n \"x\": false,\n \"q\": \"1.0000\",\n \"V\": \"500\",\n \"Q\": \"0.500\",\n \"B\": \"123456\"\n }\n}";
candlesticks.addCandlestick(s);
candlesticks.printCandlestick(candlesticks.accessDataAtIndex(0));
// WebSocket endpoint
std::string host = "wss://stream.binance.com";
std::string port = "443";
// Create the I/O context
boost::asio::io_context ioc;
// Creates SSL context and holds certificate
ssl::context ctx{ssl::context::tlsv12_client};
tcp::resolver resolver(ioc);
// Create the WebSocket stream
websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc, ctx};
// Resolve the hostname
auto endpoints = resolver.resolve(host, port);
// Connect to the first endpoint in the list
auto ep = net::connect(get_lowest_layer(ws), endpoints);
if(! SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str()))
throw beast::system_error(
beast::error_code(
static_cast<int>(::ERR_get_error()),
net::error::get_ssl_category()),
"Failed to set SNI Hostname");
host += ':' + std::to_string(ep.port());
ws.next_layer().handshake(ssl::stream_base::client);
ws.set_option(websocket::stream_base::decorator(
[](websocket::request_type& req)
{
req.set(http::field::user_agent,
std::string(BOOST_BEAST_VERSION_STRING) +
" websocket-client-coro");
}));
boost::beast::error_code ec;
ws.handshake(host, "/ws/ethusdt@kline_5m", ec);
if(ec) {
std::cerr << "Error: " << ec.message() << std::endl;
return EXIT_FAILURE;
}
//subscription message
std::string subscription_message = create_subscription_message();
// Send the subscription message
ws.write(boost::asio::buffer(subscription_message));
// Receive messages
for (;;) {
boost::beast::multi_buffer buffer;
ws.read(buffer);
std::cout << boost::beast::make_printable(buffer.data()) << std::endl;
if (buffer.size() == 0) {
break;
}
auto message = boost::beast::buffers_to_string(buffer.data());
if (message == "ping") {
buffer.consume(buffer.size());
ws.write(boost::asio::buffer("pong"));
}
}
}
catch (std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
}
错误:WebSocket 握手被远程对等方拒绝
整个问题似乎是主机格式错误:
std::string host = "wss://stream.binance.com";
那是 url,不是 FQDN 或有效的 IP 地址。 其余部分采用 FQDN(因为它用于 TCP 地址解析、SNI 和 HTTP 主机标头)。 相反,我期望:
std::string host = "stream.binance.com";
事实上,随着这种变化,错误从
Error: resolve: Host not found (authoritative) [asio.netdb:1 at /home/sehe/custom/superboost/boost/asio/detail/resolver_service.hpp:84:5 in function 'boost::asio::detail::resolver_service<Protocol>::results_type boost::asio::detail::resolver_service<Protocol>::resolve(implementation_type&, const query_type&, boost::system::error_code&)']
进入
{"error":{"code":2,"msg":"Invalid request: request ID must be an unsigned integer"}}
Error: stream truncated [asio.ssl.stream:1]
这很好,因为它意味着连接被接受,只有你的请求是无效的。 这是你接下来要看的东西。
自包含为: Coliru
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <iomanip>
#include <iostream>
#define ONEHOUR_ONEMONTH 672
#define ONEMIN_ONEWEEK 10080
#define ONESEC_ONEDAY 86400
struct cData {
//unsigned ticks;
std::vector<std::string> what_ever;
cData(unsigned /*t*/) //: ticks(t)
{}
void addCandlestick(std::string_view cs) { what_ever.emplace_back(cs); }
std::string accessDataAtIndex(size_t idx) const { return what_ever.at(idx); }
void printCandlestick(std::string_view cs) const {
std::cout << "printCandlestick: " << quoted(cs) << std::endl;
}
};
std::string create_subscription_message() {
boost::property_tree::ptree message;
message.put("method", "SUBSCRIBE");
std::vector<std::string> streams = {"btcusdt@kline_1m"};
boost::property_tree::ptree params;
for (auto& stream : streams)
params.push_back(std::make_pair("", boost::property_tree::ptree(stream)));
message.add_child("params", params);
message.put("id", 1);
std::stringstream ss;
boost::property_tree::write_json(ss, message);
return ss.str();
}
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
using tcp = boost::asio::ip::tcp;
int main() {
try {
cData candlesticks(ONEMIN_ONEWEEK);
std::string s =
R"({
"e": "kline",
"E": 123456789,
"s": "BNBBTC",
"k": {
"t": 123400000,
"T": 123460000,
"s": "BNBBTC",
"i": "1m",
"f": 100,
"L": 200,
"o": "0.0010",
"c": "0.0020",
"h": "0.0025",
"l": "0.0015",
"v": "1000",
"n": 100,
"x": false,
"q": "1.0000",
"V": "500",
"Q": "0.500",
"B": "123456"
}
})";
candlesticks.addCandlestick(s);
candlesticks.printCandlestick(candlesticks.accessDataAtIndex(0));
// WebSocket endpoint
std::string host = "stream.binance.com";
std::string port = "443";
boost::asio::io_context ioc;
ssl::context ctx{ssl::context::tlsv12_client};
tcp::resolver resolver(ioc);
websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc, ctx};
// Resolve the hostname
auto endpoints = resolver.resolve(host, port);
// Connect to the first endpoint in the list
auto ep = net::connect(get_lowest_layer(ws), endpoints);
if (!SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str()))
throw beast::system_error(
beast::error_code(static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()),
"Failed to set SNI Hostname");
host += ':' + std::to_string(ep.port());
ws.next_layer().handshake(ssl::stream_base::client);
ws.set_option(websocket::stream_base::decorator([](websocket::request_type& req) {
req.set(http::field::user_agent,
std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client-coro");
}));
boost::beast::error_code ec;
ws.handshake(host, "/ws/ethusdt@kline_5m", ec);
if (ec) {
std::cerr << "Error: " << ec.message() << std::endl;
return EXIT_FAILURE;
}
// subscription message
std::string subscription_message = create_subscription_message();
// Send the subscription message
ws.write(boost::asio::buffer(subscription_message));
// Receive messages
for (;;) {
boost::beast::multi_buffer buffer;
ws.read(buffer);
std::cout << boost::beast::make_printable(buffer.data()) << std::endl;
if (buffer.size() == 0) {
break;
}
auto message = boost::beast::buffers_to_string(buffer.data());
if (message == "ping") {
buffer.consume(buffer.size());
ws.write(boost::asio::buffer("pong"));
}
}
} catch (std::exception const& e) {
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
}
本地 output:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.