2012-05-11 61 views
3

我試圖使用asio實現一個web服務器,但是儘管將acceptor設置爲keep-alive,當我收到一個連接時,在發送響應之後,連接套接字始終是關閉的,即使我重新從套接字讀取(爲了實現來自http的保持活動)。Asio和HTTP保持存活

我試圖在代碼中插入printfs,並且出於某種原因,在我編寫響應之後,當客戶端建立新的連接時,它會調用我的套接字上的acceptor,它不應該只使用舊的套接字並重新讀取它,而不是調用acceptor?

還是我在錯誤的方式做這些保活功能...

代碼的相關部分是:

#include "connection.hpp" 
#include <vector> 
#include <boost/bind.hpp> 
#include "connection_manager.hpp" 
#include "request_handler.hpp" 
#include <iostream> 

namespace http { 
namespace server { 

connection::connection(asio::io_service& io_service, 
    connection_manager& manager, request_handler& handler) 
    : socket_(io_service), 
    connection_manager_(manager), 
    request_handler_(handler), 
    request_parser_(new http_visitor()), 
    keep_alive_(true) 
{ 
} 

asio::ip::tcp::socket& connection::socket() 
{ 
    return socket_; 
} 

void connection::start() 
{ 
    socket_.async_read_some(asio::buffer(buffer_), 
     boost::bind(&connection::handle_read, shared_from_this(), 
     asio::placeholders::error, 
     asio::placeholders::bytes_transferred)); 
    std::cout << "In connection start" << std::endl; 
} 

void connection::stop() 
{ 
    socket_.close(); 
} 

void connection::handle_read(const asio::error_code& e, 
    std::size_t bytes_transferred) 
{ 
    if (!e) 
    { 
    boost::tribool result; 
    boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
     request_, buffer_.data(), buffer_.data() + bytes_transferred); 

    if (result) 
    { 
     request_handler_.handle_request(request_, reply_); 

     std::vector<header>::iterator hdr_it; 

     for(hdr_it = request_.headers.begin(); hdr_it != request_.headers.end();  hdr_it++) 
     { 
      if((hdr_it->name.compare("Connection") == 0) && 
       (hdr_it->value.compare("close") == 0)) 
     { keep_alive_ = false; } 
     } 

     asio::async_write(socket_, reply_.to_buffers(), 
        boost::bind(&connection::handle_write, shared_from_this(), 
        asio::placeholders::error)); 
    } 
    else if (!result) 
    { 
     reply_ = reply::stock_reply(reply::bad_request); 
     asio::async_write(socket_, reply_.to_buffers(), 
      boost::bind(&connection::handle_write, shared_from_this(), 
      asio::placeholders::error)); 
    } 
    else 
    { 
     socket_.async_read_some(asio::buffer(buffer_), 
      boost::bind(&connection::handle_read, shared_from_this(), 
      asio::placeholders::error, 
      asio::placeholders::bytes_transferred)); 
    } 
    } 
    else if (e != asio::error::operation_aborted) 
    { 
    connection_manager_.stop(shared_from_this()); 
    } 
} 

void connection::handle_write(const asio::error_code& e) 
{ 
    if (!e) 
    { 

    std::cout << keep_alive_ << std::endl; 
    if(keep_alive_) 
    { 
     buffer_.assign(0); 
     request_.clear(); 
     keep_alive_ = false; 
     start(); 
    } 
    else 
    { 
     socket_.close(); 
    } 
    } 

    if (e != asio::error::operation_aborted) 
    { 
    connection_manager_.stop(shared_from_this()); 
    } 
} 
} 
} 

#include "server.hpp" 
#include <boost/bind.hpp> 
#include <signal.h> 
#include <iostream> 

namespace http { 
namespace server { 

server::server(const std::string& address, const std::string& port, 
    const std::string& doc_root) 
    : io_service_(), 
    signals_(io_service_), 
    acceptor_(io_service_), 
    connection_manager_(), 
    new_connection_(new connection(io_service_, connection_manager_, request_handler_)), 
    request_handler_(doc_root) 
{ 
    signals_.add(SIGINT); 
    signals_.add(SIGTERM); 
    signals_.async_wait(boost::bind(&server::handle_stop, this)); 

    // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). 
    asio::ip::tcp::resolver resolver(io_service_); 
    asio::ip::tcp::resolver::query query(address, port); 
    asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); 
    acceptor_.open(endpoint.protocol()); 
    acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); 
    acceptor_.set_option(asio::ip::tcp::acceptor::keep_alive(true)); 
    acceptor_.bind(endpoint); 
    acceptor_.listen(); 
    acceptor_.async_accept(new_connection_->socket(), 
     boost::bind(&server::handle_accept, this, 
     asio::placeholders::error)); 
} 

void server::run() 
{ 
    io_service_.run(); 
} 

void server::stop() 
{ 
    io_service_.post(boost::bind(&server::handle_stop, this)); 
} 

void server::handle_accept(const asio::error_code& e) 
{ 
    if (!e) 
    { 
    std::cout << "In accept" << std::endl; 
    connection_manager_.start(new_connection_); 
    new_connection_.reset(new connection(io_service_, connection_manager_,  request_handler_)); 
    acceptor_.async_accept(new_connection_->socket(), 
     boost::bind(&server::handle_accept, this, asio::placeholders::error)); 
    } 
} 

void server::handle_stop() 
{ 
    acceptor_.close(); 
    connection_manager_.stop_all(); 
} 

} // namespace server 
} // namespace http 

在此代碼打印是「在連接啓動」,「接受」和「在連接啓動」,不應該只是第一個「在連接啓動」,當有另一個連接從同一個客戶端到服務器...

+0

你的''connection_manager_.start()'函數做了什麼? – Nick

+0

@Nick它調用新連接開始。 – Coyote21

回答

2

如果沒有代碼的完整可見性,我猜new_connection_shared_ptr,並且您沒有在任何地方保留對它的引用。這會使智能指針刪除連接並關閉套接字。

在連接析構函數中插入一個斷點並檢查是否是這種情況。

沒有看到更多的代碼,很難診斷問題。