我需要编写一个处理ssl连接(读/写字符数组)到黑盒服务器的类。我需要实现断开/连接功能。但它没有按预期工作。
用例:
handle_connect()
则返回错误connection timed out
)以下是该类的源代码以及我如何使用它:
boost::asio::io_service &mioService;
SSLHandler* mpSSLConnection;
void Connector::setupConnection()
{
try{
std::string port = std::to_string(mPort);
boost::asio::ip::tcp::resolver resolver(mioService);
boost::asio::ip::tcp::resolver::query query(mHost, port);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
// context.load_verify_file("key.pem");
if(mpSSLConnection == nullptr)
mpSSLConnection = new SSLHandler(mioService,context,iterator,this);
}catch (std::exception& e){
std::cerr << "Exception: " << e.what() << "\n";
}
// actually this line is called from outside the func
mpSSLConnection->connectToServer();
}
并像这样断开连接
void Connector::disconnect()
{
isSetDisconnectedToSrv = true;
mpSSLConnection->setIsDestructing(true);
QThread::msleep(500);
delete mpSSLConnection;
mpSSLConnection = nullptr;
// setupConnection();
isConnectedToServer =false; // we did delete the object handle the ssl connection so...
mpHandler->onServerDisconnected(); // just report to upper layer
}
最后,类源代码:
#ifndef SSLHANDLER_H
#define SSLHANDLER_H
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <queue>
#include <boost/lockfree/spsc_queue.hpp>
class Connector;
const int READ_SIZE =0;
const int READ_MSG=1;
class SSLHandler
{
public:
SSLHandler(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator, Connector* pConnector)
: socket_(io_service, context) , mEndpointIterator (endpoint_iterator) , mpConnector (pConnector),
timer_{ io_service},
isConnectionOk {false}
{
LOG_TRACE << "creating new sslhandler";
socket_.set_verify_mode(boost::asio::ssl::context::verify_none);
socket_.set_verify_callback(boost::bind(&SSLHandler::verify_certificate, this, _1, _2));
mode = READ_SIZE;
}
~SSLHandler();
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx);
void handle_connect(const boost::system::error_code& error);
void handle_handshake(const boost::system::error_code& error);
void handle_write(const boost::system::error_code& error, size_t bytes_transferred);
void handle_write_auth(const boost::system::error_code& error, size_t bytes_transferred);
void handle_read_msgsize(const boost::system::error_code& error, size_t bytes_transferred);
void handle_read_message(const boost::system::error_code& error, size_t bytes_transferred);
void connectToServer();
void do_reconnect();
void handle_reconnect_timer(boost::system::error_code ec);
void writeMessage(std::vector<char> &array);
void setRequestMsg(std::vector<char> &&array);
void setIsDestructing(bool value);
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::ip::tcp::resolver::iterator mEndpointIterator;
boost::asio::deadline_timer timer_;
char reply_[0x1 << 16]; //=65356 bytes
int mode;
uint32_t size;
std::vector<char> requestMsg;
std::vector<char> replyMsg;
Connector* mpConnector; // ptr to object compose message
std::queue<std::vector < char> > mQueueMsg;
bool isConnectionOk;
bool isDestructing =false;
private:
void writeMessageWithQueue(std::vector<char> &array);
};
#endif // SSLHANDLER_H
#include "sslhandler.h"
#include "connector.h"
#include "BoostLogger.h"
#include <QThread>
#include "boost/enable_shared_from_this.hpp"
SSLHandler::~SSLHandler()
{
LOG_FATAL << "ssl handler shutdown";
if(isConnectionOk){
socket_.lowest_layer().close();
boost::system::error_code ec;
socket_.shutdown(ec);
if(ec){
LOG_FATAL << "ssl handler socket shutdown with err: " << ec.message();
}
LOG_TRACE << "ssl handler shutdown complete";
}
}
bool SSLHandler::verify_certificate(bool preverified, boost::asio::ssl::verify_context &ctx)
{
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying:\n" << subject_name << std::endl;
return preverified;
}
void SSLHandler::handle_connect(const boost::system::error_code &error)
{
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
LOG_TRACE << "get past destructing";
if(!error){
isConnectionOk = true;
LOG_TRACE << "Connection OK!" << std::endl;
socket_.async_handshake(boost::asio::ssl::stream_base::client, boost::bind(&SSLHandler::handle_handshake, this, boost::asio::placeholders::error));
}else{
LOG_FATAL << "Connect failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_handshake(const boost::system::error_code &error)
{
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
if(!error){
std::cout << "Sending request: " << std::endl;
boost::asio::async_write(socket_,
boost::asio::buffer(requestMsg.data(), requestMsg.size()),
boost::bind(&SSLHandler::handle_write_auth, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}else{
LOG_FATAL << "Handshake failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_write(const boost::system::error_code &error, size_t bytes_transferred)
{
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
if (error) {
LOG_FATAL << "Write failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
Q_UNUSED(bytes_transferred);
usleep(1e4);
if (!mQueueMsg.empty()) {
mQueueMsg.pop();
if(!mQueueMsg.empty()){
auto msg = mQueueMsg.front();
writeMessageWithQueue(msg);
}
}
else{
LOG_ERROR << "Empty queue messages!";
}
}
void SSLHandler::handle_write_auth(const boost::system::error_code &error, size_t bytes_transferred)
{
usleep(1e5);
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
if (!error){
if(mode==READ_SIZE){
mode = READ_MSG;
std::cerr << "\nSending request read size OK!\n" << std::endl;
// char respond[bytes_transferred] = "";
boost::asio::async_read(socket_, boost::asio::buffer(reply_,4),
boost::bind(&SSLHandler::handle_read_msgsize,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
// std::cerr << "respond is " ;
}
}else{
LOG_FATAL << "Write failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_read_msgsize(const boost::system::error_code &error, size_t bytes_transferred)
{
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
if (!error){
//first 4 bytes contain size of message
size = getFirstFour();
mode = READ_SIZE;
boost::asio::async_read(socket_, boost::asio::buffer(reply_,size),
boost::bind(&SSLHandler::handle_read_message,
this,
// mWriteId++,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}else{
LOG_FATAL << "Read failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_read_message(const boost::system::error_code &error, size_t bytes_transferred)
{
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
if (!error){
replyMsg.clear();
replyMsg.assign(reply_,reply_+ size);
mpConnector->setReadMsg(replyMsg);
mode = READ_SIZE;
// read next message size
boost::asio::async_read(socket_, boost::asio::buffer(reply_,4),
boost::bind(&SSLHandler::handle_read_msgsize,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}else{
LOG_FATAL << "Read failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::connectToServer()
{
// boost::asio::ip::tcp::resolver r(socket_.get_io_service());
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
boost::asio::async_connect(socket_.lowest_layer(), mEndpointIterator, boost::bind(&SSLHandler::handle_connect, this, boost::asio::placeholders::error));
LOG_TRACE << "async_connect called";
}
void SSLHandler::do_reconnect()
{
// return;
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
// socket_.shutdown();
isConnectionOk = false;
else{
socket_.lowest_layer().cancel();
timer_.expires_from_now(boost::posix_time::millisec(500));
timer_.async_wait(boost::bind(&SSLHandler::handle_reconnect_timer, this, boost::asio::placeholders::error()));
}
}
void SSLHandler::handle_reconnect_timer(boost::system::error_code ec)
{
if(!ec){
connectToServer();
}
else{
LOG_TRACE << "Error with reconnect timer : " << ec.message();
}
}
void SSLHandler::writeMessageWithQueue(std::vector<char> &array)
{
// std::cerr << "write : " << (void*) array.data() << " | " << array.size() << std::endl;
if(isDestructing){
LOG_TRACE << "Is destructing ssl connect so abort " ;
return;
}
boost::asio::async_write(socket_,
boost::asio::buffer(array.data(), array.size()),
boost::bind(&SSLHandler::handle_write, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void SSLHandler::writeMessage(std::vector<char> &array)
{
if(mQueueMsg.size()==0){
mQueueMsg.push(array);
writeMessageWithQueue(array);
}
else
mQueueMsg.push(array);
}
void SSLHandler::setRequestMsg(std::vector<char> &&array)
{
requestMsg = std::move(array);
}
void SSLHandler::setIsDestructing(bool value)
{
LOG_INFO << "ssl connection destructing set as " << value;
isDestructing = value;
if(isDestructing == true){
if(isConnectionOk){
socket_.lowest_layer().cancel();
// socket_.shutdown();
LOG_INFO << "ssl connection destructing get pass shutdown";
}
}
}
PS:这是handler tracking,这很奇怪,在(调用)disconnect()
之后再次重新连接:没有被解雇,所以建立连接后没有握手:(
@asio | 1521627714.863517 | 0 | resolver@0x7fbe2affc898.cancel空fz params!清空fz规则!清空fz param!@asio ____________ socket_: 0x7fbe10005150 @asio ____________ 192.168.2.36 @asio | 1521627714.864161 | 0 * 1 | socket@0x7fbe10005150.async_connect @asio: 连接叫@asio | 1521627714.865136 |&gt; 1 | ec = system:0 @asio | 1521627714.865375 | 1 * 2 | socket@0x7fbe10005150.async_send @asio | 1521627714.865416 |&LT; 1 | @asio | 1521627714.865421 |→2 | EC =系统:0,bytes_transferred = 517 @asio | 1521627714.865429 | 2 * 3 | socket@0x7fbe10005150.async_receive @asio | 1521627714.865451 |&2 | @asio | 1521627714.866829 |→3 | EC =系统:0,bytes_transferred = 994 @asio | 1521627714.867764 | 3 * 4 | socket@0x7fbe10005150.async_send @asio | 1521627714.867792 |&LT; 3 | @asio | 1521627714.867798 |→4 | EC =系统:0,bytes_transferred = 326 @asio | 1521627714.867809 | 4 * 5 | socket@0x7fbe10005150.async_receive @asio | 1521627714.867817 |&LT; 4 | @asio | 1521627714.870094 |→5 | EC =系统:0,bytes_transferred = 234 @asio | 1521627714.870271 | 5 * 6 | socket@0x7fbe10005150.async_send @asio | 1521627714.870318 |小于5 | @asio | 1521627714.870333 |→6 | EC =系统:0,bytes_transferred = 154 @asio | 1521627714.970430 | 6 * 7 | socket@0x7fbe10005150.async_receive @asio | 1521627714.970443 |&10 6 | @asio | 1521627714.970449 |大于7 | EC =系统:0,bytes_transferred = 138 @asio | 1521627714.970470 | 7 * 8 | socket@0x7fbe10005150.async_receive @asio | 1521627714.970475 |&LT; 7 | @asio | 1521627714.970479 |&GT; 8 | EC =系统:0,bytes_transferred = 0 @asio | 1521627714.971418 | 8 * 9 | socket@0x7fbe10005150.async_send @asio | 1521627714.971771 | 8 * 10 | deadline_timer@0x5290628.async_wait @asio | 1521627714.972004 | 8 * 11 | socket@0x7fbe10005150.async_receive @asio | 1521627714.972012 |&LT; 8 | @asio | 1521627714.972017 |&GT; 9 | EC =系统:0,bytes_transferred = 138 @asio | 1521627714.982098 | 9 * 12 | socket@0x7fbe10005150.async_send @asio | 1521627714.982115 |Δ9 | @asio | 1521627714.982121 |&GT; 12 | EC =系统:0,bytes_transferred = 138 @asio | 1521627714.992214 | 12 * 13 | socket@0x7fbe10005150.async_send @asio | 1521627714.992244 |&LT; 12 | @asio | 1521627714.992255 |&GT; 11 | EC =系统:0,bytes_transferred = 292 @asio | 1521627714.992278 | 11 * 14 | socket@0x7fbe10005150.async_receive @asio | 1521627714.992284 |&LT; 11 | @asio | 1521627714.992290 |&GT; 13 | EC =系统:0,bytes_transferred = 186 @asio | 1521627715.002355 |δ13 | @asio | 1521627715.002363 |&GT; 14 | EC =系统:0,bytes_transferred = 0 @asio | 1521627715.002469 | 14 * 15 | socket@0x7fbe10005150.async_receive @asio | 1521627715.002479 |&LT; 14 | @asio | 1521627715.002487 |→15 | EC =系统:0,bytes_transferred = 0 @asio | 1521627715.002495 | 15 * 16 | socket@0x7fbe10005150.async_receive @asio | 1521627715.002500 |&LT; 15 | @asio | 1521627715.002505 |&GT; 16 | EC =系统:0,bytes_transferred = 0 @asio | 1521627715.002550 | 16 * 17 | socket@0x7fbe10005150.async_receive @asio | 1521627715.002561 |&LT; 16 | @asio | 1521627715.002566 |&GT; 17 | EC =系统:0,bytes_transferred = 154 @asio | 1521627715.002581 | 17 * 18 | socket@0x7fbe10005150.async_receive @asio | 1521627715.002586 |&LT; 17 | @asio | 1521627715.002590 |&GT; 18 | EC =系统:0,bytes_transferred = 0 @asio | 1521627715.002636 | 18 * 19 | socket@0x7fbe10005150.async_receive @asio | 1521627715.002653 |&LT; 18 | @asio | 1521627721.861983 |→10 | EC =系统:0 @asio | 1521627721.862105 | 10 * 20 | socket@0x7fbe10005150.async_send @asio | 1521627721.862139 | 10 | deadline_timer@0x5290628.cancel @asio | 1521627721.862144 | 10 * 21 | deadline_timer@0x5290628.async_wait @asio | 1521627721.862258 |&LT; 10 | @asio | 1521627721.862268 |→20 | EC =系统:0,bytes_transferred = 138 @asio | 1521627721.872365 |&小于20 | @asio | 1521627721.872398 |&GT; 19 | EC =系统:0,bytes_transferred = 138 @asio | 1521627721.872436 | 19 * 22 | socket@0x7fbe10005150.async_receive @asio | 1521627721.872443 |&LT; 19 | @asio | 1521627721.872447 |&GT; 22 | EC =系统:0,bytes_transferred = 0 @asio | 1521627721.872503 | 22 * 23 | socket@0x7fbe10005150.async_receive @asio | 1521627721.872515 |&LT; 22 | @asio | 1521627724.861966 |&GT; 21 | EC =系统:0 @asio | 1521627724.862091 | 21 * 24 | socket@0x7fbe10005150.async_send @asio | 1521627724.862148 | 21 | deadline_timer@0x5290628.cancel @asio | 1521627724.862157 | 21 * 25 | deadline_timer@0x5290628.async_wait @asio | 1521627724.862272 |&LT; 21 | @asio | 1521627724.862286 |&GT; 24 | EC =系统:0,bytes_transferred = 138 @asio | 1521627724.872375 |&LT; 24 | @asio | 1521627724.872409 |&GT; 23 | EC =系统:0,bytes_transferred = 138 @asio | 1521627724.872457 | 23 * 26 | socket@0x7fbe10005150.async_receive @asio | 1521627724.872465 |&LT; 23 | @asio | 1521627724.872469 |&GT; 26 | EC =系统:0,bytes_transferred = 0 @asio | 1521627724.872510 | 26 * 27 | socket@0x7fbe10005150.async_receive @asio | 1521627724.872516 |&LT; 26 | @asio | 1521627727.861968 |→25 | EC =系统:0 @asio | 1521627727.862084 | 25 * 28 | socket@0x7fbe10005150.async_send @asio | 1521627727.862120 | 25 | deadline_timer@0x5290628.cancel @asio | 1521627727.862125 | 25 * 29 | deadline_timer@0x5290628.async_wait @asio | 1521627727.862204 |&LT; 25 | @asio | 1521627727.862211 |&GT; 28 | EC =系统:0,bytes_transferred = 138 @asio | 1521627727.872283 |&LT; 28 | @asio | 1521627727.872314 |&GT; 27 | EC =系统:0,bytes_transferred = 138 @asio | 1521627727.872362 | 27 * 30 | socket@0x7fbe10005150.async_receive @asio | 1521627727.872366 |&LT; 27 | @asio | 1521627727.872371 |→30 | EC =系统:0,bytes_transferred = 0 @asio | 1521627727.872412 | 30 * 31 | socket@0x7fbe10005150.async_receive @asio | 1521627727.872418 |小于30 | @asio | 1521627730.861967 |&GT; 29 | EC =系统:0 @asio | 1521627730.862072 | 29 * 32 | socket@0x7fbe10005150.async_send @asio | 1521627730.862118 | 29 | deadline_timer@0x5290628.cancel @asio | 1521627730.862125 | 29 * 33 | deadline_timer@0x5290628.async_wait @asio | 1521627730.862217 |&LT; 29 | @asio | 1521627730.862227 |&GT; 32 | EC =系统:0,bytes_transferred = 138 @asio | 1521627730.872315 |&LT; 32 | @asio | 1521627730.872360 |&GT; 31 | EC =系统:0,bytes_transferred = 138 @asio | 1521627730.872406 | 31 * 34 | socket@0x7fbe10005150.async_receive @asio | 1521627730.872412 |&LT; 31 | @asio | 1521627730.872416 |&GT; 34 | EC =系统:0,bytes_transferred = 0 @asio | 1521627730.872458 | 34 * 35 | socket@0x7fbe10005150.async_receive @asio | 1521627730.872465 |&LT; 34 | @asio | 1521627733.862001 |&GT; 33 | EC =系统:0 @asio | 1521627733.862114 | 33 * 36 | socket@0x7fbe10005150.async_send @asio | 1521627733.862153 | 33 | deadline_timer@0x5290628.cancel @asio | 1521627733.862158 | 33 * 37 | deadline_timer@0x5290628.async_wait @asio | 1521627733.862244 |γ-33 | @asio | 1521627733.862250 |&GT; 36 | EC =系统:0,bytes_transferred = 138 @asio | 1521627733.872342 |&LT; 36 | @asio | 1521627733.872379 |→35 | EC =系统:0,bytes_transferred = 138 @asio | 1521627733.872416 | 35 * 38 | socket@0x7fbe10005150.async_receive @asio | 1521627733.872422 |&γ-35 | @asio | 1521627733.872424 |&GT; 38 | EC =系统:0,bytes_transferred = 0 @asio | 1521627733.872461 | 38 * 39 | socket@0x7fbe10005150.async_receive @asio | 1521627733.872466 |&LT; 38 | @asio | 1521627736.861976 |&在37 | EC =系统:0 @asio | 1521627736.862158 | 37 * 40 | socket@0x7fbe10005150.async_send @asio | 1521627736.862235 | 37 | deadline_timer@0x5290628.cancel @asio | 1521627736.862242 | 37 * 41 | deadline_timer@0x5290628.async_wait @asio | 1521627736.862406 |&{37 | @asio | 1521627736.862414 |→40 | EC =系统:0,bytes_transferred = 138 @asio | 1521627736.872497 |&LT; 40 | @asio | 1521627736.872555 |&GT; 39 | EC =系统:0,bytes_transferred = 138 @asio | 1521627736.872622 | 39 * 42 | socket@0x7fbe10005150.async_receive @asio | 1521627736.872638 |&LT; 39 | @asio | 1521627736.872641 |&GT; 42 | EC =系统:0,bytes_transferred = 0 @asio | 1521627736.872720 | 42 * 43 | socket@0x7fbe10005150.async_receive @asio | 1521627736.872726 |&LT; 42 | @asio | 1521627739.861978 |&GT; 41 | EC =系统:0 @asio | 1521627739.862096 | 41 * 44 | socket@0x7fbe10005150.async_send @asio | 1521627739.862144 | 41 | deadline_timer@0x5290628.cancel @asio | 1521627739.862148 | 41 * 45 | deadline_timer@0x5290628.async_wait @asio | 1521627739.862243 |&LT; 41 | @asio | 1521627739.862249 |&GT; 44 | EC =系统:0,bytes_transferred = 138 @asio | 1521627739.872335 |&LT; 44 | @asio | 1521627739.872375 |&GT; 43 | EC =系统:0,bytes_transferred = 138 @asio | 1521627739.872421 | 43 * 46 | socket@0x7fbe10005150.async_receive @asio | 1521627739.872425 |&LT; 43 | @asio | 1521627739.872429 |&GT; 46 | EC =系统:0,bytes_transferred = 0 @asio | 1521627739.872477 | 46 * 47 | socket@0x7fbe10005150.async_receive @asio | 1521627739.872492 |&LT; 46 | @asio | 1521627742.861953 |&GT; 45 | EC =系统:0 @asio | 1521627742.862121 | 45 * 48 | socket@0x7fbe10005150.async_send @asio | 1521627742.862204 | 45 | deadline_timer@0x5290628.cancel @asio | 1521627742.862211 | 45 * 49 | deadline_timer@0x5290628.async_wait @asio | 1521627742.862392 |&LT; 45 | @asio | 1521627742.862406 |&GT; 48 | EC =系统:0,bytes_transferred = 138 @asio | 1521627742.872491 |&LT; 48 | @asio | 1521627742.872543 |&GT; 47 | EC =系统:0,bytes_transferred = 138 @asio | 1521627742.872592 | 47 * 50 | socket@0x7fbe10005150.async_receive @asio | 1521627742.872600 |&LT; 47 | @asio | 1521627742.872605 |→50 | EC =系统:0,bytes_transferred = 0 @asio | 1521627742.872675 | 50 * 51 | socket@0x7fbe10005150.async_receive @asio | 1521627742.872688 |&LT; 50 | @asio | 1521627745.316714 | 0 | socket@0x7fbe10005150.close @asio | 1521627745.316777 |&GT; 51 | EC =系统:125,bytes_transferred = 0 @asio | 1521627745.316858 |的51 | @asio:~SSLHandler @asio | 1521627745.817594 | 0 | resolver@0x7fbe00ff8758.cancel @asio | 1521627745.861965 |&gt; 49 | ec = system:0 @asio | 1521627745.861984 |&lt; 49 | @asio | 1521627749.757091 | 0 | resolver@0x7fbe00ff8648.cancel @asio____________ socket_:0x7fbde4008890 @asio ____________ 192.168.2.36 @asio | 1521627749.757178 | 0 * 52 | socket@0x7fbde4008890.async_connect @asio:connect called
答案 0 :(得分:1)
我修复了自包含的样本,并将其运行到演示服务器上:
#include <iostream>
#include <sstream>
#include <vector>
#ifdef STANDALONE
namespace {
struct LogTx {
std::stringstream _ss;
std::ostream& _os;
bool _armed = true;
LogTx(std::ostream& os) : _os(os) {}
LogTx(LogTx&& rhs) : _ss(std::move(rhs._ss)), _os(rhs._os) { rhs._armed = false; }
~LogTx() { if (_armed) _os << _ss.rdbuf() << std::endl; }
LogTx operator<<(std::ostream&(&v)(std::ostream&)) { _ss << v; return std::move(*this); }
template <typename T> LogTx operator<<(T&& v) { _ss << v; return std::move(*this); }
};
}
# define LOG_FATAL LogTx(std::cerr) << "FATAL: "
# define LOG_TRACE LogTx(std::clog) << "TRACE: "
# define LOG_ERROR LogTx(std::cerr) << "ERROR: "
# define LOG_INFO LogTx(std::clog) << "INFO: "
# define Q_UNUSED(a) static_cast<void>(a)
namespace {
struct Connector {
void sendDisconnectedStatus() { LOG_INFO << "Disconnected"; }
void setReadMsg(std::vector<char> const& v) { LOG_INFO << "response: '" << std::string(v.begin(), v.end()) << "'"; }
};
}
#endif
#ifndef SSLHANDLER_H
#define SSLHANDLER_H
#include <boost/endian/arithmetic.hpp> // for big_uint32_t
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <queue>
#include <string>
#include <thread>
const int READ_SIZE = 0;
const int READ_MSG = 1;
class SSLHandler {
public:
SSLHandler(boost::asio::io_service &io_service, boost::asio::ssl::context &context,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator, Connector *pConnector)
: socket_(io_service, context), mEndpointIterator(endpoint_iterator),
mpConnector(pConnector), timer_{ io_service }, isConnectionOk{ false }
{
LOG_TRACE << "creating new sslhandler";
socket_.set_verify_mode(boost::asio::ssl::context::verify_none);
socket_.set_verify_callback(boost::bind(&SSLHandler::verify_certificate, this, _1, _2));
mode = READ_SIZE;
}
~SSLHandler();
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context &ctx);
void handle_connect(const boost::system::error_code &error);
void handle_handshake(const boost::system::error_code &error);
void handle_write(const boost::system::error_code &error, size_t bytes_transferred);
void handle_write_auth(const boost::system::error_code &error, size_t bytes_transferred);
void handle_read_msgsize(const boost::system::error_code &error, size_t bytes_transferred);
void handle_read_message(const boost::system::error_code &error, size_t bytes_transferred);
void connectToServer();
void do_reconnect();
void handle_reconnect_timer(boost::system::error_code ec);
void writeMessage(std::vector<char> &array);
void setRequestMsg(std::vector<char> &&array);
void setIsDestructing(bool value);
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::ip::tcp::resolver::iterator mEndpointIterator;
Connector *mpConnector; // ptr to object compose message
boost::asio::deadline_timer timer_;
char reply_[0x1 << 16]; //=65356 bytes
size_t getFirstFour() {
return *boost::asio::buffer_cast<boost::endian::big_uint32_t *>(boost::asio::buffer(reply_));
};
int mode;
uint32_t size;
std::vector<char> requestMsg;
std::vector<char> replyMsg;
std::queue<std::vector<char> > mQueueMsg;
bool isConnectionOk;
bool isDestructing = false;
private:
void writeMessageWithQueue(std::vector<char> &array);
};
#endif // SSLHANDLER_H
//#include "sslhandler.h"
//#include "connector.h"
//#include "BoostLogger.h"
//#include <QThread>
//#include "boost/enable_shared_from_this.hpp"
SSLHandler::~SSLHandler() {
LOG_FATAL << "ssl handler shutdown";
if (isConnectionOk) {
socket_.lowest_layer().close();
boost::system::error_code ec;
socket_.shutdown(ec);
if (ec) {
LOG_FATAL << "ssl handler socket shutdown with err: " << ec.message();
}
LOG_TRACE << "ssl handler shutdown complete";
}
}
bool SSLHandler::verify_certificate(bool preverified, boost::asio::ssl::verify_context &ctx) {
char subject_name[256];
X509 *cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying:\n" << subject_name << std::endl;
return preverified;
}
void SSLHandler::handle_connect(const boost::system::error_code &error) {
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
LOG_TRACE << "get past destructing";
if (!error) {
isConnectionOk = true;
LOG_TRACE << "Connection OK!" << std::endl;
socket_.async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&SSLHandler::handle_handshake, this, boost::asio::placeholders::error));
} else {
LOG_FATAL << "Connect failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_handshake(const boost::system::error_code &error) {
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
if (!error) {
std::cout << "Sending request: " << std::endl;
boost::asio::async_write(socket_, boost::asio::buffer(requestMsg.data(), requestMsg.size()),
boost::bind(&SSLHandler::handle_write_auth, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
} else {
LOG_FATAL << "Handshake failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_write(const boost::system::error_code &error, size_t bytes_transferred) {
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
if (error) {
LOG_FATAL << "Write failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
Q_UNUSED(bytes_transferred);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if (!mQueueMsg.empty()) {
mQueueMsg.pop();
if (!mQueueMsg.empty()) {
auto msg = mQueueMsg.front();
writeMessageWithQueue(msg);
}
} else {
LOG_ERROR << "Empty queue messages!";
}
}
void SSLHandler::handle_write_auth(const boost::system::error_code &error, size_t bytes_transferred) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
if (!error) {
if (mode == READ_SIZE) {
mode = READ_MSG;
std::cerr << "\nSending request read size OK!\n" << std::endl;
// char respond[bytes_transferred] = "";
boost::asio::async_read(socket_, boost::asio::buffer(reply_, 4),
boost::bind(&SSLHandler::handle_read_msgsize, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
// std::cerr << "respond is " ;
}
} else {
LOG_FATAL << "Write failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_read_msgsize(const boost::system::error_code &error, size_t bytes_transferred) {
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
if (!error) {
// first 4 bytes contain size of message
size = getFirstFour();
LOG_TRACE << "Decoded size: " << size;
mode = READ_SIZE;
boost::asio::async_read(socket_, boost::asio::buffer(reply_, size),
boost::bind(&SSLHandler::handle_read_message, this,
// mWriteId++,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
} else {
LOG_FATAL << "Read failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::handle_read_message(const boost::system::error_code &error, size_t bytes_transferred) {
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
if (!error) {
replyMsg.clear();
replyMsg.assign(reply_, reply_ + size);
mpConnector->setReadMsg(replyMsg);
mode = READ_SIZE;
// read next message size
boost::asio::async_read(socket_, boost::asio::buffer(reply_, 4),
boost::bind(&SSLHandler::handle_read_msgsize, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
} else {
LOG_FATAL << "Read failed: " << error.message() << std::endl;
mpConnector->sendDisconnectedStatus();
do_reconnect();
}
}
void SSLHandler::connectToServer() {
// boost::asio::ip::tcp::resolver r(socket_.get_io_service());
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
boost::asio::async_connect(socket_.lowest_layer(), mEndpointIterator,
boost::bind(&SSLHandler::handle_connect, this, boost::asio::placeholders::error));
LOG_TRACE << "async_connect called";
}
void SSLHandler::do_reconnect() {
// socket_.shutdown();
isConnectionOk = false;
// return;
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
} else {
socket_.lowest_layer().cancel();
timer_.expires_from_now(boost::posix_time::millisec(500));
timer_.async_wait(boost::bind(&SSLHandler::handle_reconnect_timer, this, boost::asio::placeholders::error()));
}
}
void SSLHandler::handle_reconnect_timer(boost::system::error_code ec) {
if (!ec) {
connectToServer();
} else {
LOG_TRACE << "Error with reconnect timer : " << ec.message();
}
}
void SSLHandler::writeMessageWithQueue(std::vector<char> &array) {
// std::cerr << "write : " << (void*) array.data() << " | " << array.size() << std::endl;
if (isDestructing) {
LOG_TRACE << "Is destructing ssl connect so abort ";
return;
}
boost::asio::async_write(socket_, boost::asio::buffer(array.data(), array.size()),
boost::bind(&SSLHandler::handle_write, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void SSLHandler::writeMessage(std::vector<char> &array) {
if (mQueueMsg.size() == 0) {
mQueueMsg.push(array);
writeMessageWithQueue(array);
}
else
mQueueMsg.push(array);
}
void SSLHandler::setRequestMsg(std::vector<char> &&array) { requestMsg = std::move(array); }
void SSLHandler::setIsDestructing(bool value) {
LOG_INFO << "ssl connection destructing set as " << value;
isDestructing = value;
if (isDestructing == true) {
if (isConnectionOk) {
socket_.lowest_layer().cancel();
// socket_.shutdown();
LOG_INFO << "ssl connection destructing get pass shutdown";
}
}
}
int main() {
Connector c;
boost::asio::io_service svc;
boost::asio::ssl::context ctx(boost::asio::ssl::context_base::sslv23_client);
SSLHandler h(svc, ctx, boost::asio::ip::tcp::resolver{svc}.resolve({{}, 6767}), &c);
h.setRequestMsg({'h','e','l','l','o','\n','w','o','r','l','d'});
h.connectToServer();
svc.run();
}
现在,我没有看到任何问题,无论服务器在中断后需要多长时间才能恢复。
你提到
嗨,我的意思是用户主动呼叫断开功能(不像上次那样通过网络丢弃连接)。如果用户调用disconnect()然后等待超过10秒,则调用connect()连接失败,错误:连接超时。 - 巴顿11 hours ago
您的代码中没有disconnect()
这样的功能,也无法看到它可能如何实现。因此,