【发布时间】:2020-06-17 11:30:08
【问题描述】:
我正在尝试基于套接字创建一个 https 服务器并将其分发到不同的流中。如果一切都在同一个线程上进行,服务器本身工作正常,可以稳定地保持负载和处理请求。如果我把它放在不同的线程中,那么在负载(wrk)下测试时,服务器崩溃......我的代码:
#include <cstdio>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <boost/thread.hpp>
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <iostream>
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
class session
{
public:
session(boost::asio::io_context& io_context,
boost::asio::ssl::context& context)
: socket_(io_context, context)
{
}
ssl_socket::lowest_layer_type& socket()
{
return socket_.lowest_layer();
}
void start()
{
socket_.async_handshake(boost::asio::ssl::stream_base::server,
boost::bind(&session::handle_handshake, this,
boost::asio::placeholders::error));
}
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
int req_rah = 0;
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
std::string Result_test = "HTTP/1.1 200 OK\r\n" +
std::string("Content-Length: 2\r\n") +
std::string("Content-Type: text/html\r\n") +
std::string("Connection: Closed\r\n\r\n") +
std::string("ok") +
std::string("\r\n");
boost::asio::streambuf request_test;
std::ostream request_stream_test(&request_test);
request_stream_test << Result_test;
boost::asio::write(socket_, request_test);
boost::asio::async_write(socket_,
request_test,
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
private:
ssl_socket socket_;
enum { max_length = 6291456 };
char data_[max_length] = "";
};
class server
{
public:
server(boost::asio::io_context& io_context, unsigned short port)
: io_context_(io_context),
acceptor_(io_context,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
context_(boost::asio::ssl::context::sslv23)
{
context_.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
context_.set_password_callback(boost::bind(&server::get_password, this));
context_.use_certificate_chain_file("Server.crt");
context_.use_private_key_file("Server.key", boost::asio::ssl::context::pem);
context_.use_tmp_dh_file("dh2048.pem");
start_accept();
}
std::string get_password() const
{
return "";
}
void start_accept()
{
session* new_session = new session(io_context_, context_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
}
else
{
delete new_session;
}
start_accept();
}
private:
boost::asio::io_context& io_context_;
boost::asio::ip::tcp::acceptor acceptor_;
boost::asio::ssl::context context_;
};
int main(int argc,
char *argv[],
char *envp[])
{
try
{
boost::asio::io_context io_context;
boost::thread_group pool;
server s(io_context, 8080);
for (auto i = 0u; i<boost::thread::hardware_concurrency(); ++i)
pool.create_thread([&] {io_context.run(); });
pool.join_all();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
当从浏览器https://127.0.0.1:8080 访问所有规则时,我得到“ok”。执行 wrk 时,一切都崩溃了...据我了解,线程处理不正确(阅读或/和回答),遇到类似任务的人请帮忙,出了什么问题...提前致谢!
【问题讨论】:
-
您在
handle_read中有UB。request_test是本地的,因为您调用async_write所以函数会立即结束,而request_testas local 也会被销毁。为什么你首先调用write,然后调用async_write,使用相同的源缓冲区? -
关于“write and later async_write”这是我发布代码时的错误,抱歉。关于本地 request_test 我不明白,它必须是公开的?...
-
本地我的意思是一种保存变量的存储。在函数中,变量存储在堆栈中(称为本地)。您不能将对局部变量的引用传递给
async_write,因为在由async_write发起的异步任务内部,对该变量的引用将悬空。
标签: c++ sockets c++11 boost boost-asio