2012-05-11 20 views
3

私はasioを使ってWebサーバーを実装しようとしていますが、受け入れ側をキープアライブとして設定していても、接続を受信すると、私がソケットから再読み込みしたとしても(httpからキープアライブを実装するために)。AsioとHTTPキープアライブ

私はコードにprintfsを挿入しようとしましたが、何らかの理由でレスポンスを書き込んだ後、クライアントが新しい接続を確立したときに、ソケット上のアクセプタが呼び出されます。 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 

このコードでは:コードの関連部分がある

または私は間違った方法でキープアライブ機能をしています... "In connection start"、 "In accept"、および "In connection start"というプリントは、同じクライアントからサーバへの別の接続がある場合、最初の「接続開始」であるべきではありません。

+0

'connection_manager_.start()'関数は何をしますか? – Nick

+0

@Nick新しい接続でstartを呼び出します。 – Coyote21

答えて

2

コードの完全な可視性がないと、私はnew_connection_shared_ptrであり、どこにもその参照を保持していないと推測しています。これによりスマートポインタは接続を削除し、ソケットを閉じます。

接続デストラクターにブレークポイントを設定して、これが当てはまるかどうかを確認します。

もっとコードを見ることなく、問題を診断するのは難しいです。

関連する問題