C++ 中的 Websocket 客户端使用 boost::Beast - 在写操作时抛出错误
Websocket client in C++ using boost::Beast - throwing error at write operation
下面是一段代码,我正在努力让它成功。我使用 git 集线器 https://www.boost.org/doc/libs/1_70_0/libs/beast/doc/html/beast/quick_start/websocket_client.html 上提供的参考代码。
问题是当我调用连接方法并在它工作的同一个函数中执行写操作时,但是如果我把它放在不同的函数中它就不会工作。
我是 boost 的新手,shared_pointer,如果我没有任何意义,请原谅。
// Sends a WebSocket message and prints the response
class CWebSocket_Sync : public std::enable_shared_from_this<CWebSocket_Sync>
{
tcp::resolver resolver_;
websocket::stream<tcp::socket> ws_;
boost::beast::multi_buffer buffer_;
std::string host_;
std::string text_;
public:
// Resolver and socket require an io_context
explicit
CWebSocket_Sync(boost::asio::io_context& ioc)
: resolver_(ioc)
, ws_(ioc)
{
}
void
connect(
char const* host,
char const* port,
char const* text)
{
// Save these for later
host_ = host;
text_ = text;
// Look up the domain name
auto const results = resolver_.resolve(host, port);
// Make the connection on the IP address we get from a lookup
auto ep = net::connect(ws_.next_layer(), results);
// Update the host_ string. This will provide the value of the
// Host HTTP header during the WebSocket handshake.
// See https://tools.ietf.org/html/rfc7230#section-5.4
host_ += ':' + std::to_string(ep.port());
// Perform the websocket handshake
ws_.handshake(host_, "/");
//ws_.write(net::buffer(std::string(text)));
//// This buffer will hold the incoming message
//beast::flat_buffer buffer;
//// Read a message into our buffer
//ws_.read(buffer);
}
void ServerCommand(char const* text)
{
ws_.write(net::buffer(std::string(text))); // <-- this line throw memory error
// This buffer will hold the incoming message
beast::flat_buffer buffer;
// Read a message into our buffer
ws_.read(buffer);
// The make_printable() function helps print a ConstBufferSequence
std::cout << beast::make_printable(buffer.data()) << std::endl;
}
void CloseConnection()
{
// Close the WebSocket connection
ws_.close(websocket::close_code::normal);
}
};
int main(int argc, char** argv)
{
auto const host = "127.0.0.1";
auto const port = "7011";
auto const loginCmd = "login"
boost::asio::io_context ioc;
std::make_shared<CWebSocket_Sync>(ioc)->connect(host, port, loginCmd);
std::make_shared<CWebSocket_Sync>(ioc)->ServerCommand(loginCmd);
std::make_shared<CWebSocket_Sync>(ioc)->CloseConnection();
return EXIT_SUCCESS;
}
std::make_shared<CWebSocket_Sync>(ioc)->connect(host, port);
std::make_shared<CWebSocket_Sync>(ioc)->ServerCommand(loginCmd);
std::make_shared<CWebSocket_Sync>(ioc)->CloseConnection();
每行创建一个新客户端 (make_shared<CWebSocket_Sync>
) 并在其上运行一个步骤。你可能想要什么:
auto client = std::make_shared<CWebSocket_Sync>(ioc);
client->connect(host, port);
client->ServerCommand(loginCmd);
client->CloseConnection();
确实有效:
#include <boost/beast.hpp>
#include <boost/beast/websocket.hpp>
#include <memory>
#include <iostream>
namespace net = boost::asio;
namespace beast = boost::beast;
namespace websocket = beast::websocket;
using net::ip::tcp;
// Sends a WebSocket message and prints the response
class CWebSocket_Sync : public std::enable_shared_from_this<CWebSocket_Sync> {
tcp::resolver resolver_;
websocket::stream<tcp::socket> ws_;
boost::beast::multi_buffer buffer_;
std::string host_;
public:
// Resolver and socket require an io_context
explicit CWebSocket_Sync(boost::asio::io_context& ioc)
: resolver_(ioc), ws_(ioc) { }
void connect(char const* host, char const* port) {
// Save these for later
host_ = host;
// Look up the domain name
auto const results = resolver_.resolve(host, port);
// Make the connection on the IP address we get from a lookup
auto ep = net::connect(ws_.next_layer(), results);
// Update the host_ string. This will provide the value of the
// Host HTTP header during the WebSocket handshake.
// See https://tools.ietf.org/html/rfc7230#section-5.4
host_ += ':' + std::to_string(ep.port());
// Perform the websocket handshake
ws_.handshake(host_, "/");
}
void ServerCommand(char const* text) {
ws_.write(net::buffer(std::string(text))); // <-- this line throw memory error
beast::flat_buffer buffer;
ws_.read(buffer);
std::cout << beast::make_printable(buffer.data()) << std::endl;
}
void CloseConnection() {
ws_.close(websocket::close_code::normal);
}
};
int main() {
auto const host = "127.0.0.1";
auto const port = "7011";
auto const loginCmd = "login";
boost::asio::io_context ioc;
auto client = std::make_shared<CWebSocket_Sync>(ioc);
client->connect(host, port);
client->ServerCommand(loginCmd);
client->CloseConnection();
}
简化
但是,由于没有任何东西使用共享生命周期并且您没有在任何地方使用异步调用,为什么不简单地:
class CWebSocket_Sync {
及以后:
CWebSocket_Sync client(ioc);
client.connect(host, port);
client.ServerCommand(loginCmd);
client.CloseConnection();
下面是一段代码,我正在努力让它成功。我使用 git 集线器 https://www.boost.org/doc/libs/1_70_0/libs/beast/doc/html/beast/quick_start/websocket_client.html 上提供的参考代码。 问题是当我调用连接方法并在它工作的同一个函数中执行写操作时,但是如果我把它放在不同的函数中它就不会工作。
我是 boost 的新手,shared_pointer,如果我没有任何意义,请原谅。
// Sends a WebSocket message and prints the response
class CWebSocket_Sync : public std::enable_shared_from_this<CWebSocket_Sync>
{
tcp::resolver resolver_;
websocket::stream<tcp::socket> ws_;
boost::beast::multi_buffer buffer_;
std::string host_;
std::string text_;
public:
// Resolver and socket require an io_context
explicit
CWebSocket_Sync(boost::asio::io_context& ioc)
: resolver_(ioc)
, ws_(ioc)
{
}
void
connect(
char const* host,
char const* port,
char const* text)
{
// Save these for later
host_ = host;
text_ = text;
// Look up the domain name
auto const results = resolver_.resolve(host, port);
// Make the connection on the IP address we get from a lookup
auto ep = net::connect(ws_.next_layer(), results);
// Update the host_ string. This will provide the value of the
// Host HTTP header during the WebSocket handshake.
// See https://tools.ietf.org/html/rfc7230#section-5.4
host_ += ':' + std::to_string(ep.port());
// Perform the websocket handshake
ws_.handshake(host_, "/");
//ws_.write(net::buffer(std::string(text)));
//// This buffer will hold the incoming message
//beast::flat_buffer buffer;
//// Read a message into our buffer
//ws_.read(buffer);
}
void ServerCommand(char const* text)
{
ws_.write(net::buffer(std::string(text))); // <-- this line throw memory error
// This buffer will hold the incoming message
beast::flat_buffer buffer;
// Read a message into our buffer
ws_.read(buffer);
// The make_printable() function helps print a ConstBufferSequence
std::cout << beast::make_printable(buffer.data()) << std::endl;
}
void CloseConnection()
{
// Close the WebSocket connection
ws_.close(websocket::close_code::normal);
}
};
int main(int argc, char** argv)
{
auto const host = "127.0.0.1";
auto const port = "7011";
auto const loginCmd = "login"
boost::asio::io_context ioc;
std::make_shared<CWebSocket_Sync>(ioc)->connect(host, port, loginCmd);
std::make_shared<CWebSocket_Sync>(ioc)->ServerCommand(loginCmd);
std::make_shared<CWebSocket_Sync>(ioc)->CloseConnection();
return EXIT_SUCCESS;
}
std::make_shared<CWebSocket_Sync>(ioc)->connect(host, port);
std::make_shared<CWebSocket_Sync>(ioc)->ServerCommand(loginCmd);
std::make_shared<CWebSocket_Sync>(ioc)->CloseConnection();
每行创建一个新客户端 (make_shared<CWebSocket_Sync>
) 并在其上运行一个步骤。你可能想要什么:
auto client = std::make_shared<CWebSocket_Sync>(ioc);
client->connect(host, port);
client->ServerCommand(loginCmd);
client->CloseConnection();
确实有效:
#include <boost/beast.hpp>
#include <boost/beast/websocket.hpp>
#include <memory>
#include <iostream>
namespace net = boost::asio;
namespace beast = boost::beast;
namespace websocket = beast::websocket;
using net::ip::tcp;
// Sends a WebSocket message and prints the response
class CWebSocket_Sync : public std::enable_shared_from_this<CWebSocket_Sync> {
tcp::resolver resolver_;
websocket::stream<tcp::socket> ws_;
boost::beast::multi_buffer buffer_;
std::string host_;
public:
// Resolver and socket require an io_context
explicit CWebSocket_Sync(boost::asio::io_context& ioc)
: resolver_(ioc), ws_(ioc) { }
void connect(char const* host, char const* port) {
// Save these for later
host_ = host;
// Look up the domain name
auto const results = resolver_.resolve(host, port);
// Make the connection on the IP address we get from a lookup
auto ep = net::connect(ws_.next_layer(), results);
// Update the host_ string. This will provide the value of the
// Host HTTP header during the WebSocket handshake.
// See https://tools.ietf.org/html/rfc7230#section-5.4
host_ += ':' + std::to_string(ep.port());
// Perform the websocket handshake
ws_.handshake(host_, "/");
}
void ServerCommand(char const* text) {
ws_.write(net::buffer(std::string(text))); // <-- this line throw memory error
beast::flat_buffer buffer;
ws_.read(buffer);
std::cout << beast::make_printable(buffer.data()) << std::endl;
}
void CloseConnection() {
ws_.close(websocket::close_code::normal);
}
};
int main() {
auto const host = "127.0.0.1";
auto const port = "7011";
auto const loginCmd = "login";
boost::asio::io_context ioc;
auto client = std::make_shared<CWebSocket_Sync>(ioc);
client->connect(host, port);
client->ServerCommand(loginCmd);
client->CloseConnection();
}
简化
但是,由于没有任何东西使用共享生命周期并且您没有在任何地方使用异步调用,为什么不简单地:
class CWebSocket_Sync {
及以后:
CWebSocket_Sync client(ioc);
client.connect(host, port);
client.ServerCommand(loginCmd);
client.CloseConnection();