我构造了一个套接字客户端和服务器,并使用它进行本地通信
构建是好的,但当运行在根特权(绑定()需要根),套接字得到了错误的版本,而握手。
为简单起见,错误代码如下:
握手时()
在写入时()
Beast版本:1.70.0
代码:
ClientService.cc
// Client Connect to Server
void ClientService::Connect(const std::string &host, unsigned int port) {
const auto id = (unsigned int)(mpSLAM->GetMap()->mnId);
mThread = new std::thread([this, host, port, id] {
auto const text = "Hello, world!";
info("client {} connect to host {} port {}", id, host, port);
// The io_context is required for all I/O
boost::asio::io_context ioc;
work_guard_type workGuard(ioc.get_executor());
const std::string specify_local_address = "0.0.0.0";
unsigned int specify_local_portnumber = 20000;
info("In connection: client bind to local endpoint host {} port {}", specify_local_address, specify_local_portnumber);
// Launch the asynchronous operation, which would call WebSocket.h
auto session = std::make_shared<WS::Client::session>(ioc, specify_local_address.c_str(), reinterpret_cast<unsigned int *>(specify_local_portnumber),
std::bind(&ClientService::OnRequest, this, std::placeholders::_1));
this->service = session;
session->run(host.c_str(), reinterpret_cast<unsigned int *>(port), text);
// Run the I/O service. The call will return when
// the socket is closed.
ioc.run();
});
}
void ClientService::SendRequest(const Request &req) {
// serialize and send request
std::string msg = ORB_SLAM2::toString(req);
this->service->send(make_shared<std::string>(msg));
}
客户端的WebSocket. h
namespace Client {
// Sends a WebSocket message and prints the response
class session : public std::enable_shared_from_this<session> {
// we do not need a resolver since itself initialize a connection
// tcp::resolver resolver_;
// websocket::stream <tcp::socket> ws_;
websocket::stream <beast::tcp_stream> ws_;
// beast::tcp_stream ws_;
beast::flat_buffer buffer_;
std::vector<std::shared_ptr<const std::string>> queue;
std::string host_;
std::uint8_t port_;
std::function<void(const std::string&)> on_message;
std::string localhost_;
std::uint8_t localport_;
//the constructor
public:
// Resolver and socket require an io_context
explicit
session(net::io_context &ioc, char const *localhost, unsigned int *localport, std::function<void(const std::string&)> on_message)
: ws_(net::make_strand(ioc)), on_message(std::move(on_message))
{
localhost_ = localhost;
std::stringstream str_port_value;
str_port_value << localport;
str_port_value >> localport_;
beast::error_code err;
//Here I've bind the local endpoint
beast::get_lowest_layer(ws_).socket().open(boost::asio::ip::tcp::v4(), err);
beast::get_lowest_layer(ws_).socket().bind(tcp::endpoint(boost::asio::ip::make_address_v4(localhost_), localport_));
}
// Start the asynchronous operation
void
run(
char const *host,
unsigned int *port,
__attribute__((unused)) char const *text) {
// Save these for later
host_ = host;
std::stringstream str_port_value;
str_port_value << port;
str_port_value >> port_;
// dropped the resolver
// resolver_.async_resolve(
// host,
// port,
// beast::bind_front_handler(
// &session::on_resolve,
// shared_from_this()));
//construct a tcp::endpoint using ip::address_v4 and port number
tcp::endpoint ep(boost::asio::ip::address::from_string(host_.c_str()), port_);
beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
//here just connect to ep without resolver
beast::get_lowest_layer(ws_).socket().async_connect(
ep,
beast::bind_front_handler(
&session::on_connect,
shared_from_this()));
}
void
// on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep) {
on_connect(beast::error_code ec)
{
// get the ep parameter from run() as ep_
tcp::endpoint ep_(boost::asio::ip::address::from_string(host_.c_str()), port_);
if (ec)
return fail(ec, "connect");
// Turn off the timeout on the tcp_stream, because
// the websocket stream has its own timeout system.
beast::get_lowest_layer(ws_).expires_never();
// Set suggested timeout settings for the websocket
ws_.set_option(
websocket::stream_base::timeout::suggested(
beast::role_type::client));
// output on screen said making a handshake with server
std::cout << "Making a handshake with server" << std::endl;
//where possibly go wrong
// Set a decorator to change the User-Agent of the handshake
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-async");
}));
// update the host string. This will provide the value of the
// host HTTP header during the websocket handshake
// the guide references: https://tools.ietf.org/html/rfc7230#section-5.4
host_ += ':' + std::to_string(ep_.port());
// Perform the websocket handshake
ws_.async_handshake(host_, "/",
beast::bind_front_handler(
&session::on_handshake,
shared_from_this()));
}
void
on_handshake(beast::error_code ec) {
//here comes the error code
if (ec)
return fail(ec, "handshake");
buffer_.consume(buffer_.size());
net::post(ws_.get_executor(), beast::bind_front_handler(&session::on_read, shared_from_this(), ec, 5));
std::cout << "Handshake successful." << std::endl;
}
void
on_write(
beast::error_code ec,
std::size_t bytes_transferred) {
boost::ignore_unused(bytes_transferred);
//another error code
if (ec)
return fail(ec, "write");
queue.erase(queue.begin());
// send the message if any
if (!queue.empty()) {
ws_.async_write(net::buffer(*queue.front()),
beast::bind_front_handler(&session::on_write, shared_from_this()));
}
}
服务器的WebSocket. h
public:
// Take ownership of the socket
explicit
session(tcp::socket &&socket, std::shared_ptr<shared_state> state, std::function<void(std::string)> on_message)
: ws_(std::move(socket)), state(std::move(state)), on_message(std::move(on_message)) {
}
~session() {
std::cout << "~session()" << std::endl;
state->leave(this);
}
// Start the asynchronous operation
void
run() {
// Set suggested timeout settings for the websocket
ws_.set_option(
websocket::stream_base::timeout::suggested(
beast::role_type::server));
// Set a decorator to change the Server of the handshake
ws_.set_option(websocket::stream_base::decorator(
[](websocket::response_type &res) {
res.set(http::field::server,
std::string(BOOST_BEAST_VERSION_STRING) +
" websocket-server-async");
}));
// Accept the websocket handshake
ws_.async_accept(
beast::bind_front_handler(
&session::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec) {
if (ec)
return fail(ec, "accept");
state->join(this);
// Read a message
do_read();
}
运行日志:
[11:07:16][3518][I][注册远程:70]正在注册远程客户端
[11:07:16][3518][I][注册号:172]客户端绑定到本地端点主机0.0.0.0端口20001
[11:07:16][3518][I][注册号:173]客户端注册到主机0.0.0.0端口10088
小行星12330
[11:07:16][3518][I][注册远程:79]已注册客户端,其ID为:1和端口:2330
[11:07:16][3518][I][远程寄存器:85]正在连接到数据通道
[11:07:16][3518][I][远程寄存器:89]已连接到数据通道
[11:07:16][3533][I][operator():39]客户端1连接到主机0.0.0.0端口2330
[11:07:16][3533][I][运算符():54]在连接中:客户端绑定到本地端点主机0.0.0.0端口20000
正在与服务器握手
握手:错误版本
GTK-消息:十一点零七分十六点二九七分加载模块“canberra-gtk-module”失败
write:操作已取消
在我删除解析器并修改绑定本地端点的代码之前,它工作得很好。
但我没有修改握手的部分。
并且不能看到在调试模式下发生了什么,因为它直接进入了写操作。
密码有错吗?
还是我用了websocket::stream <beast::tcp_stream> ws_;
尽管它在原始代码中使用
如有任何帮助和指导,我将不胜感激,谢谢!
1条答案
按热度按时间5kgi1eie1#
至少在端口号上有很多bug,你将无符号数字重新解释为...指针,然后通过写入字符串流和返回来转换,但是...转换为
uint8_t
,难怪**你"需要root"才能执行bind
:前1024个端口是特权端口。除此之外,你还在做一些奇怪的事情
work_guard
,因为您稍后将使用数据块io_context::run()
来完成所有工作error_code
bind
-客户端套接字上的ing;这是非常罕见的--这可能是你想要的,尽管我不特别知道为什么consume()
-ing从未使用过的缓冲区session
示例设置this->service
;如果线程所做的只是运行io上下文,那么为什么首先要有线程呢?io_context
属于单个线程on_write
,因此没有任何东西将开始写入(queue
不在on_write
之外使用)on_read
手动,与一个虚假的大小5
?我在same Beast example的基础上添加了一个
listener
,使其自包含以重现您的消息:本地输出:
这里明显的错误是我连接到了客户端本身的本地绑定端口
20'000
!修复到20'001
(或任何运行服务器的端口):奖金
解决更多上述问题,并添加实际功能:
本地测试输出: