Refine the draft timeout control from server side.

master
Adam Gu 7 years ago
parent fb37d759a0
commit 919fa54a98

@ -3,8 +3,6 @@
#include <list> #include <list>
#include "boost/lexical_cast.hpp" #include "boost/lexical_cast.hpp"
#include "boost/thread.hpp"
#include "boost/date_time/posix_time/posix_time.hpp"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -115,10 +113,6 @@ bool BookListService::Handle(const std::string& http_method,
std::string* response_content) { std::string* response_content) {
if (http_method == webcc::kHttpGet) { if (http_method == webcc::kHttpGet) {
*response_content = CreateBookListJson(g_book_store.books()); *response_content = CreateBookListJson(g_book_store.books());
// Sleep for testing timeout control.
//boost::this_thread::sleep(boost::posix_time::seconds(2));
return true; return true;
} }
@ -146,9 +140,6 @@ bool BookDetailService::Handle(const std::string& http_method,
*response_content = CreateBookJson(book); *response_content = CreateBookJson(book);
// Sleep for testing timeout control.
//boost::this_thread::sleep(boost::posix_time::seconds(2));
return true; return true;
} else if (http_method == webcc::kHttpPost) { } else if (http_method == webcc::kHttpPost) {

@ -27,11 +27,6 @@ int main(int argc, char* argv[]) {
server.RegisterService(std::make_shared<BookDetailService>(), server.RegisterService(std::make_shared<BookDetailService>(),
"/books/(\\d+)"); "/books/(\\d+)");
// For test purpose.
// Timeout like 60s makes more sense in a real product.
// Leave it as default (0) for no timeout control.
server.set_timeout_seconds(1);
server.Run(); server.Run();
} catch (std::exception& e) { } catch (std::exception& e) {

@ -16,8 +16,7 @@ namespace webcc {
HttpServer::HttpServer(unsigned short port, std::size_t workers) HttpServer::HttpServer(unsigned short port, std::size_t workers)
: signals_(io_context_) : signals_(io_context_)
, workers_(workers) , workers_(workers) {
, timeout_seconds_(0) {
// Register to handle the signals that indicate when the server should exit. // Register to handle the signals that indicate when the server should exit.
// It is safe to register for the same signal multiple times in a program, // It is safe to register for the same signal multiple times in a program,
@ -78,7 +77,7 @@ void HttpServer::DoAccept() {
HttpSessionPtr session{ HttpSessionPtr session{
new HttpSession(std::move(socket), GetRequestHandler()) new HttpSession(std::move(socket), GetRequestHandler())
}; };
session->Start(timeout_seconds_); session->Start();
} }
DoAccept(); DoAccept();

@ -28,10 +28,6 @@ public:
virtual ~HttpServer(); virtual ~HttpServer();
void set_timeout_seconds(long seconds) {
timeout_seconds_ = seconds;
}
// Run the server's io_service loop. // Run the server's io_service loop.
void Run(); void Run();
@ -57,10 +53,6 @@ private:
// Acceptor used to listen for incoming connections. // Acceptor used to listen for incoming connections.
boost::scoped_ptr<boost::asio::ip::tcp::acceptor> acceptor_; boost::scoped_ptr<boost::asio::ip::tcp::acceptor> acceptor_;
// Timeout in seconds for socket connection.
// Default is 0 which means no timeout.
long timeout_seconds_;
}; };
} // namespace webcc } // namespace webcc

@ -22,27 +22,13 @@ HttpSession::HttpSession(boost::asio::ip::tcp::socket socket,
HttpSession::~HttpSession() { HttpSession::~HttpSession() {
} }
void HttpSession::Start(long timeout_seconds) { void HttpSession::Start() {
if (timeout_seconds > 0) {
// Create timer only necessary.
boost::asio::io_context& ioc = socket_.get_executor().context();
timer_.reset(new boost::asio::deadline_timer(ioc));
timer_->expires_from_now(boost::posix_time::seconds(timeout_seconds));
timer_->async_wait(std::bind(&HttpSession::HandleTimer,
shared_from_this(),
std::placeholders::_1));
}
DoRead(); DoRead();
} }
void HttpSession::Stop() { void HttpSession::Stop() {
CancelTimer(); boost::system::error_code ec;
socket_.close(ec);
boost::system::error_code ignored_ec;
socket_.close(ignored_ec);
} }
void HttpSession::SetResponseContent(const std::string& content_type, void HttpSession::SetResponseContent(const std::string& content_type,
@ -78,8 +64,6 @@ void HttpSession::HandleRead(boost::system::error_code ec,
if (ec) { if (ec) {
if (ec != boost::asio::error::operation_aborted) { if (ec != boost::asio::error::operation_aborted) {
Stop(); Stop();
} else {
CancelTimer();
} }
return; return;
} }
@ -116,53 +100,25 @@ void HttpSession::HandleWrite(boost::system::error_code ec,
#endif #endif
if (!ec) { if (!ec) {
CancelTimer(); #if WEBCC_DEBUG_OUTPUT
std::cout << "Response has been sent back (thread: " << thread_id << ")\n";
#endif
// Initiate graceful connection closure. // Initiate graceful connection closure.
boost::system::error_code ec; boost::system::error_code ec;
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
#if WEBCC_DEBUG_OUTPUT
std::cout << "Response has been sent back (thread: " << thread_id << ")\n";
#endif
} else { } else {
#if WEBCC_DEBUG_OUTPUT #if WEBCC_DEBUG_OUTPUT
std::cout << "(thread: " << thread_id << ") Sending response error: " std::cout << "(thread: " << thread_id << ") Sending response error: "
<< ec.message() << ec.message()
<< std::endl; << std::endl;
#endif #endif
if (ec == boost::asio::error::operation_aborted) { if (ec != boost::asio::error::operation_aborted) {
CancelTimer();
} else {
Stop(); Stop();
} }
} }
} }
void HttpSession::HandleTimer(boost::system::error_code ec) {
std::cout << "HandleTimer: ";
if (!ec) {
if (socket_.is_open()) {
std::cout << "socket is open, close it.\n";
socket_.close();
} else {
std::cout << "socket is not open.\n";
}
} else {
if (ec == boost::asio::error::operation_aborted) {
std::cout << "Timer aborted\n";
}
}
}
void HttpSession::CancelTimer() {
if (timer_) {
// The wait handler will be invoked with the operation_aborted error code.
boost::system::error_code ec;
timer_->cancel(ec);
}
}
} // namespace webcc } // namespace webcc

@ -5,7 +5,6 @@
#include <memory> #include <memory>
#include "boost/asio/ip/tcp.hpp" // for ip::tcp::socket #include "boost/asio/ip/tcp.hpp" // for ip::tcp::socket
#include "boost/asio/deadline_timer.hpp"
#include "webcc/common.h" #include "webcc/common.h"
#include "webcc/http_request.h" #include "webcc/http_request.h"
@ -30,8 +29,7 @@ public:
return request_; return request_;
} }
// Start the session with an optional timeout. void Start();
void Start(long timeout_seconds = 0);
void Stop(); void Stop();
@ -54,17 +52,10 @@ private:
void HandleRead(boost::system::error_code ec, std::size_t length); void HandleRead(boost::system::error_code ec, std::size_t length);
void HandleWrite(boost::system::error_code ec, std::size_t length); void HandleWrite(boost::system::error_code ec, std::size_t length);
void HandleTimer(boost::system::error_code ec);
void CancelTimer();
private: private:
// Socket for the connection. // Socket for the connection.
boost::asio::ip::tcp::socket socket_; boost::asio::ip::tcp::socket socket_;
// Timeout timer (optional).
std::unique_ptr<boost::asio::deadline_timer> timer_;
// The handler used to process the incoming request. // The handler used to process the incoming request.
HttpRequestHandler* request_handler_; HttpRequestHandler* request_handler_;

Loading…
Cancel
Save