执行boost::asio::async_write时错误

Write:Unitialized Error when performing boost::asio::async_write

本文关键字:write 错误 async boost asio 执行      更新时间:2023-10-16

我已经分配使用boost::asio创建一个HTTPS服务器,所以我确实在互联网上花了一些时间,并找到了一个来源,解释了我们如何将boost HTTP及其SSL功能结合在一起,这在boost官方网站中没有解释。一切都已经好现在我在执行阶段,这就是玫瑰心灵恶心的问题,我在我的代码构建请求流我用boost::asio::async_write交付,在运行时,我收到一个错误就像下面,我很确信boost::asio::async_write造成的,但我不确定是什么导致了它,谁能解释对我来说,我一直徘徊在黑暗中:((请参见下面的代码)

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
  what():  write: uninitialized
 using boost::asio::ip::tcp;
 string my_password_callback(size_t, boost::asio::ssl::context_base::password_purpose);
 void handle_resolve(const boost::system::error_code& ,
                        tcp::resolver::iterator);
 bool verify_certificate();
 void handle_read();
 void handle_write();

    int i,j,rc;
    sqlite3 *db;
    string selectsql;
    sqlite3_stmt *stmt;
    char *zErrMsg = 0;
    stringstream ss;
    boost::asio::io_service io_service1;
    boost::asio::io_service &io_service(io_service1);
    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
    boost::asio::ssl::context& context_=ctx;
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_(io_service,context_);
int main()
{
    boost::shared_ptr<boost::asio::ssl::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(my_password_callback);
    context_.use_certificate_chain_file("SSL\test.crt");
    context_.use_private_key_file("SSL\test.key", boost::asio::ssl::context::pem);
    tcp::resolver resolver_(io_service);
    tcp::resolver::query query("172.198.72.135:3000", "http");
    resolver_.async_resolve(query,boost::bind(handle_resolve,
                                           boost::asio::placeholders::error,
                                            boost::asio::placeholders::iterator));
    boost::asio::streambuf request;
    string path="https://172.198.72.135:3000/journals/enc_data?";
while(true)
{
    char * EJTEXT;
    int ID;
    if(sqlite3_open("c:\MinGW\test.db", &db))
    {
    selectsql="select IEJ,EJ from EJ limit 1";
    sqlite3_prepare_v2(db, selectsql.c_str(), -1, &stmt, NULL);
    if(sqlite3_step(stmt)==SQLITE_ROW){
    ID=sqlite3_column_int(stmt,0);
    EJTEXT=(char *)sqlite3_column_text(stmt,1);
    }
    else{
    }
   sqlite3_finalize(stmt);
   sqlite3_close(db);
    }
    string EJ=EJTEXT;
     E.Encrypt(EJ);
     string data=E.Url_safe(E.cipher);--my logic
     string Iv=E.Url_safe(E.encoded_iv);--my logic
     std::ostream request_stream(&request);
     request_stream << "POST " <<path+"Data="+data+"&"+"iv="+Iv;
     request_stream << "Host: " <<"172.198.72.135"<< "rn";
     request_stream << "Accept: */*rn";
     request_stream << "Connection: closernrn";
    //try{
   boost::asio::async_write(socket_, request,
       boost::asio::transfer_at_least(1),
        boost::bind(handle_write));
temp="";
data="";
Iv="";
    boost::asio::streambuf response; 
    std::istream response_stream(&response);
    std::string http_version;
    response_stream >> http_version;
    unsigned int status_code;
    response_stream >> status_code;
    std::string status_message;
    std::getline(response_stream, status_message);
    if (!response_stream || http_version.substr(0, 5) != "HTTP/")
    {
      l.HTTP_SSLLOG("Invalid response");
    }
    if (status_code== 200)
    {
     string deletesql="delete * from EJ where IEJ="+ID;
     if(sqlite3_open("c:\MinGW\test.db", &db))
    {
    rc=sqlite3_exec(db, deletesql.c_str(), 0, 0, &zErrMsg);
    sqlite3_close(db);
    if(rc)
    {
        ss<<ID;
        l.EJ_Log("ERROR DELETING EJ FOR  "+ss.str());
    }
    }
    else{
        l.DB_Log("ERROR OPENING DB");
    }
    }
    else{
    continue;
}
Sleep(6000);
}
 return 0;
}
 string my_password_callback(size_t t, boost::asio::ssl::context_base::password_purpose p)//std::size_t max_length,ssl::context::password_purpose purpose )
   {
    std::string password;
    return "balaji";
   }
   void handle_resolve(const boost::system::error_code& err,
                        tcp::resolver::iterator endpoint_iterator)
    {
        if (!err)
        {
            socket_.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
            socket_.set_verify_callback(boost::bind(verify_certificate));
            boost::asio::connect(socket_.lowest_layer(), endpoint_iterator);
        }
        else
        {
            l.HTTP_SSLLOG("Error resolve: "+err.message());
        }
    }
    bool verify_certificate()
    {
    bool preverified =true;
    context_.set_default_verify_paths();
    return preverified;
    }
    void handle_read()
       {
       }
    void handle_write()
    {
     boost::asio::async_read_until(socket_, response, "rn",
          boost::bind(handle_read));

    }  

异步操作被设计成不抛出异常,而是将错误传递给完成处理程序作为它们的第一个参数(boost::system::error_code)。例如,下面的程序演示了async_write()失败并出现未初始化的错误:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
int main()
{
  boost::asio::io_service io_service;
  boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
  boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(io_service, ctx);  
  boost::asio::async_write(socket, boost::asio::buffer("demo"), 
    [](const boost::system::error_code& error, std::size_t bytes_transferred)
    {
      std::cout << error.message() << std::endl;
    });
  io_service.run();
}

以上程序将输出uninitialized。如果从异步操作中抛出异常,则强烈提示正在调用未定义行为。

根据发布的代码,async_write()操作可能违反了底层缓冲区内存的所有权由调用者保留的要求,调用者必须保证它在处理程序被调用之前保持有效。在这种情况下,while循环的下一次迭代可能会使提供给前一次迭代的async_write()操作的缓冲区失效。

然而,即使没有未定义的行为,也会有额外的问题,因为程序既不尝试建立连接,也不执行SSL握手,这两者都必须在通过加密连接发送或接收数据之前完成。


当使用异步操作时,作为整个操作流一部分的while-sleep循环通常是代码异味的指示。考虑删除sqlite3和加密代码,并首先启动并运行SSL原型。它还可以帮助编译启用最高警告级别/迂腐标志。的提振。Asio SSL概述显示了一个典型的同步使用模式:

using boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
typedef ssl::stream<tcp::socket> ssl_socket;
// Create a context that uses the default paths for
// finding CA certificates.
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
// Open a socket and connect it to the remote host.
boost::asio::io_service io_service;
ssl_socket sock(io_service, ctx);
tcp::resolver resolver(io_service);
tcp::resolver::query query("host.name", "https");
boost::asio::connect(sock.lowest_layer(), resolver.resolve(query));
sock.lowest_layer().set_option(tcp::no_delay(true));
// Perform SSL handshake and verify the remote host's
// certificate.
sock.set_verify_mode(ssl::verify_peer);
sock.set_verify_callback(ssl::rfc2818_verification("host.name"));
sock.handshake(ssl_socket::client);
// ... read and write as normal ...

官方SSL示例也可以作为使用异步操作的一个很好的起点或参考。一旦确认SSL原型可以正常工作,然后将sqlite3和加密逻辑添加回程序中。

另外,在使用多个线程的情况下,要注意SSL流不是线程安全的。所有异步操作必须通过显式链进行同步。对于组合操作,例如async_write(),必须在strand的上下文中调用初始化函数,并且完成处理程序必须由相同的strand包装。