我正在尝试使用来自here的Boost ASIO示例代码编写基于SSL的异步服务器。
我在客户端正确获取第一条消息及其响应。然后,我发送第二条消息,该消息在服务器上收到,但是当响应被发送到客户端时。它有点胡言乱语。
我已将服务器代码上传到pastebin。另外,请在下面找到:
// file - Server.h
class Server
{
public:
explicit Server(const std::string &address,
int port,
std::size_t threadPoolSize);
// run the io_service loop
void run();
// stop the server
void stop();
private:
//handle async accept operation
void handleAccept(const boost::system::error_code &e);
// number of threads in thread pool
std::size_t _threadPoolSize;
// the io_service
boost::asio::io_service _ioService;
// acceptor to listen for incoming connections
boost::asio::ip::tcp::acceptor _acceptor;
std::string get_password()
{
return "password";
}
// ssl context
boost::asio::ssl::context _context;
ConnectionPtr _connection;
};
//////////////////////////////////////////////////////////////////////////
// file - Server.cpp
//////////////////////////////////////////////////////////////////////////
Server::Server(const std::string& address,
int port,
std::size_t threadPoolSize)
: _threadPoolSize(threadPoolSize),
_acceptor(_ioService),
_context(_ioService, boost::asio::ssl::context::sslv23),
_connection()
{
try {
DEBUG_2("Starting server on port: ", port);
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
_acceptor.open(endpoint.protocol());
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
_acceptor.bind(endpoint);
_acceptor.listen();
_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("./demoCA/cacert.pem");
_context.use_private_key_file("./demoCA/private/cakey.pem",
boost::asio::ssl::context::pem);
// _context.use_tmp_dh_file("dh512.pem");
_connection.reset(new CclConnection(_ioService, _context));
_acceptor.async_accept(_connection->socket(),
boost::bind(&Server::handleAccept,
this,
boost::asio::placeholders::error));
}
catch(std::exception& e)
{
STD_EXCEPTION_MESSAGE;
throw;
}
}
void Server::run()
{
// Create a pool of threads to run all of the io_services.
std::vector<boost::shared_ptr<boost::thread> > threads;
for (std::size_t i = 0; i < _threadPoolSize; ++i)
{
boost::shared_ptr<boost::thread>
thread(new boost::thread(
boost::bind(&boost::asio::io_service::run,
&_ioService)
)
);
threads.push_back(thread);
}
// Wait for all threads in the pool to exit.
for (std::size_t i = 0; i < threads.size(); ++i)
threads[i]->join();
}
void Server::stop()
{
_ioService.stop();
}
void Server::handleAccept(const boost::system::error_code& e)
{
if (!e)
{
_connection->handshake();
_connection.reset(new CclConnection(_ioService, _context));
_acceptor.async_accept(_connection->socket(),
boost::bind(&Server::handleAccept,
this,
boost::asio::placeholders::error));
}
}
////////////////////////////////////////////////////////////
// file - Connection.h
////////////////////////////////////////////////////////////
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
typedef boost::asio::ssl::stream< boost::asio::ip::tcp::socket >
ssl_socket;
class Connection
: public boost::enable_shared_from_this<Connection>
{
public:
explicit Connection(boost::asio::io_service& io_service,
boost::asio::ssl::context& context);
//get socket from the connection
ssl_socket::lowest_layer_type& socket();
// do an SSL handshake
void handshake();
//get socket from the connection
boost::asio::io_service::strand& strand();
// start first async operation
void start();
void sendResponse(const Response& response);
void close();
// get remote IP address for this connection
std::string getIPAddress();
private:
void handleRead(const boost::system::error_code& e,
std::size_t bytesTransferred);
void handleWrite(const boost::system::error_code& e);
boost::asio::io_service::strand _strand;
ssl_socket _socket;
void handleHandshake(const boost::system::error_code& e);
boost::array<char, 8192> _buffer;
};
typedef boost::shared_ptr<Connection> ConnectionPtr;
///////////////////////////////////////////////////////////////
// File - Connection.cpp
///////////////////////////////////////////////////////////////
Connection::Connection(boost::asio::io_service& io_service,
boost::asio::ssl::context& context)
: _strand(io_service),
_socket(io_service, context)
{
}
ssl_socket::lowest_layer_type& Connection::socket()
{
return _socket.lowest_layer();
}
boost::asio::io_service::strand& Connection::strand()
{
return _strand;
}
void Connection::start()
{
_socket.async_read_some(boost::asio::buffer(_buffer),
_strand.wrap(
boost::bind(
&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
)
);
}
void Connection::handshake()
{
std::cout << "doing ssl handshake" << std::endl;
_socket.async_handshake(boost::asio::ssl::stream_base::server,
_strand.wrap(
boost::bind(
&Connection::handleHandshake,
shared_from_this(),
boost::asio::placeholders::error
)
)
);
}
void Connection::handleHandshake(const boost::system::error_code& error)
{
if (!error)
{
_socket.async_read_some(boost::asio::buffer(_buffer),
_strand.wrap(
boost::bind(
&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
)
);
}
else
{
std::cout << "error occured: " << error.message();
this->close();
}
}
void Connection::handleRead(const boost::system::error_code& e,
std::size_t bytesTransferred)
{
if (!e) {
// handle read data
this->start();
}
else {
this->close();
}
}
void Connection::handleWrite(const boost::system::error_code& e)
{
if (!e) {
this->start();
}
else {
this->close();
}
}
void Connection::sendResponse(const Response& response)
{
boost::asio::async_write(_socket,
boost::asio::buffer(convertToString(response)),
_strand.wrap(
boost::bind(
&Connection::handleWrite,
shared_from_this(),
boost::asio::placeholders::error
)
)
);
}
void Connection::close()
{
boost::system::error_code ignoredCode;
socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignoredCode);
}
std::string Connection::getIPAddress()
{
return socket().remote_endpoint().address().to_string();
}
有人能指出我在这里做错了什么吗?
更新:我在评论中指出问题已得到解决。该问题与stackoverflow上的另一个old question完全相似。
答案 0 :(得分:2)
您的代码无法识别,boost::asio::buffer
只是构建它的对象包装器。
在这里(Connection::sendResponse
):
boost::asio::buffer(convertToString(response))
您在(可能)临时对象中创建了缓冲区,在boost::asio::async_write
使用之前已被销毁。
Boost.Asio documentation specifically tells you about that
对于接受类型参数的boost :: asio :: buffer重载 std :: string,返回的缓冲区对象根据无效 为引用,指针和引号的无效定义的规则 迭代器引用序列的元素(C ++ Std,21.3)。