add log for study server threading

master
Chunting Gu 4 years ago
parent d65ca13b7d
commit 74854c4861

@ -27,17 +27,20 @@ int main(int argc, const char* argv[]) {
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
int workers = 1; int workers = 1;
int loops = 1;
int sleep_seconds = 0; int sleep_seconds = 0;
if (argc > 1) { if (argc > 1) {
workers = std::stoi(argv[1]); workers = std::stoi(argv[1]);
if (argc > 2) { if (argc > 2) {
sleep_seconds = std::stoi(argv[2]); loops = std::stoi(argv[2]);
if (argc > 3) {
sleep_seconds = std::stoi(argv[3]);
}
} }
} }
LOG_USER("Workers: %d", workers); LOG_USER("Workers: %d, loops: %d, sleep: %ds", workers, loops, sleep_seconds);
LOG_USER("Sleep seconds: %d", sleep_seconds);
try { try {
webcc::Server server{ boost::asio::ip::tcp::v4(), 8080 }; webcc::Server server{ boost::asio::ip::tcp::v4(), 8080 };
@ -46,7 +49,7 @@ int main(int argc, const char* argv[]) {
server.Route("/", view); server.Route("/", view);
server.Route("/hello", view); server.Route("/hello", view);
server.Run(workers); server.Run(workers, loops);
} catch (const std::exception&) { } catch (const std::exception&) {
return 1; return 1;

@ -28,7 +28,7 @@ void Connection::Start() {
} }
request_parser_.Init(request_.get(), view_matcher_); request_parser_.Init(request_.get(), view_matcher_);
DoRead(); AsyncRead();
} }
void Connection::Close() { void Connection::Close() {
@ -68,7 +68,7 @@ void Connection::SendResponse(ResponsePtr response, bool no_keep_alive) {
response_->Prepare(); response_->Prepare();
DoWrite(); AsyncWrite();
} }
void Connection::SendResponse(Status status, bool no_keep_alive) { void Connection::SendResponse(Status status, bool no_keep_alive) {
@ -82,7 +82,11 @@ void Connection::SendResponse(Status status, bool no_keep_alive) {
SendResponse(response, no_keep_alive); SendResponse(response, no_keep_alive);
} }
void Connection::DoRead() { void Connection::AsyncRead() {
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("[%u] AsyncRead()", (unsigned int)this);
#endif
socket_.async_read_some(boost::asio::buffer(buffer_), socket_.async_read_some(boost::asio::buffer(buffer_),
std::bind(&Connection::OnRead, shared_from_this(), std::bind(&Connection::OnRead, shared_from_this(),
std::placeholders::_1, std::placeholders::_1,
@ -90,6 +94,10 @@ void Connection::DoRead() {
} }
void Connection::OnRead(boost::system::error_code ec, std::size_t length) { void Connection::OnRead(boost::system::error_code ec, std::size_t length) {
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("[%u] OnRead()", (unsigned int)this);
#endif
if (ec) { if (ec) {
if (ec == boost::asio::error::eof) { if (ec == boost::asio::error::eof) {
LOG_INFO("Socket read EOF (%s)", ec.message().c_str()); LOG_INFO("Socket read EOF (%s)", ec.message().c_str());
@ -121,7 +129,7 @@ void Connection::OnRead(boost::system::error_code ec, std::size_t length) {
if (!request_parser_.finished()) { if (!request_parser_.finished()) {
// Continue to read the request. // Continue to read the request.
DoRead(); AsyncRead();
return; return;
} }
@ -132,7 +140,11 @@ void Connection::OnRead(boost::system::error_code ec, std::size_t length) {
queue_->Push(shared_from_this()); queue_->Push(shared_from_this());
} }
void Connection::DoWrite() { void Connection::AsyncWrite() {
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("[%u] AsyncWrite()", (unsigned int)this);
#endif
LOG_VERB("Response:\n%s", response_->Dump().c_str()); LOG_VERB("Response:\n%s", response_->Dump().c_str());
// Firstly, write the headers. // Firstly, write the headers.
@ -144,16 +156,20 @@ void Connection::DoWrite() {
void Connection::OnWriteHeaders(boost::system::error_code ec, void Connection::OnWriteHeaders(boost::system::error_code ec,
std::size_t length) { std::size_t length) {
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("[%u] OnWriteHeaders()", (unsigned int)this);
#endif
if (ec) { if (ec) {
OnWriteError(ec); HandleWriteError(ec);
} else { } else {
// Write the body payload by payload. // Write the body payload by payload.
response_->body()->InitPayload(); response_->body()->InitPayload();
DoWriteBody(); AsyncWriteBody();
} }
} }
void Connection::DoWriteBody() { void Connection::AsyncWriteBody() {
auto payload = response_->body()->NextPayload(); auto payload = response_->body()->NextPayload();
if (!payload.empty()) { if (!payload.empty()) {
@ -164,19 +180,23 @@ void Connection::DoWriteBody() {
std::placeholders::_2)); std::placeholders::_2));
} else { } else {
// No more body payload left, we're done. // No more body payload left, we're done.
OnWriteOK(); HandleWriteOK();
} }
} }
void Connection::OnWriteBody(boost::system::error_code ec, std::size_t length) { void Connection::OnWriteBody(boost::system::error_code ec, std::size_t length) {
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("[%u] OnWriteBody()", (unsigned int)this);
#endif
if (ec) { if (ec) {
OnWriteError(ec); HandleWriteError(ec);
} else { } else {
DoWriteBody(); AsyncWriteBody();
} }
} }
void Connection::OnWriteOK() { void Connection::HandleWriteOK() {
LOG_INFO("Response has been sent back"); LOG_INFO("Response has been sent back");
if (request_->IsConnectionKeepAlive()) { if (request_->IsConnectionKeepAlive()) {
@ -188,7 +208,7 @@ void Connection::OnWriteOK() {
} }
} }
void Connection::OnWriteError(boost::system::error_code ec) { void Connection::HandleWriteError(boost::system::error_code ec) {
LOG_ERRO("Socket write error (%s)", ec.message().c_str()); LOG_ERRO("Socket write error (%s)", ec.message().c_str());
if (ec != boost::asio::error::operation_aborted) { if (ec != boost::asio::error::operation_aborted) {

@ -13,6 +13,11 @@
#include "webcc/request_parser.h" #include "webcc/request_parser.h"
#include "webcc/response.h" #include "webcc/response.h"
// Set 1 to enable the log for the study of server thread model.
// Need to use multiple workers and loops for Server::Run().
// Suggest to configure the log level to USER.
#define WEBCC_STUDY_SERVER_THREADING 0
namespace webcc { namespace webcc {
class Connection; class Connection;
@ -27,11 +32,11 @@ public:
Queue<ConnectionPtr>* queue, ViewMatcher&& view_matcher, Queue<ConnectionPtr>* queue, ViewMatcher&& view_matcher,
std::size_t buffer_size); std::size_t buffer_size);
~Connection() = default;
Connection(const Connection&) = delete; Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete; Connection& operator=(const Connection&) = delete;
~Connection() = default;
RequestPtr request() const { RequestPtr request() const {
return request_; return request_;
} }
@ -53,16 +58,19 @@ public:
void SendResponse(Status status, bool no_keep_alive = false); void SendResponse(Status status, bool no_keep_alive = false);
private: private:
void DoRead(); void AsyncRead();
void OnRead(boost::system::error_code ec, std::size_t length); void OnRead(boost::system::error_code ec, std::size_t length);
void DoWrite(); void AsyncWrite();
void OnWriteHeaders(boost::system::error_code ec, std::size_t length); void OnWriteHeaders(boost::system::error_code ec, std::size_t length);
void DoWriteBody();
void AsyncWriteBody();
void OnWriteBody(boost::system::error_code ec, std::size_t length); void OnWriteBody(boost::system::error_code ec, std::size_t length);
void OnWriteOK();
void OnWriteError(boost::system::error_code ec);
void HandleWriteOK();
void HandleWriteError(boost::system::error_code ec);
private:
// The socket for the connection. // The socket for the connection.
boost::asio::ip::tcp::socket socket_; boost::asio::ip::tcp::socket socket_;

@ -10,10 +10,21 @@
#include "webcc/response.h" #include "webcc/response.h"
#include "webcc/utility.h" #include "webcc/utility.h"
using namespace std::placeholders;
using tcp = boost::asio::ip::tcp; using tcp = boost::asio::ip::tcp;
namespace webcc { namespace webcc {
// NOTE:
// Using `asio::strand` is possible but not neccessary:
// Define a memeber variable:
// asio::strand<asio::io_context::executor_type> strand_;
// Initialize the strand with io_context:
// strand_(asio::make_strand(io_context_)),
// Initialize the acceptor with strand:
// acceptor_(strand_)
// The same applies to the sockets.
Server::Server(boost::asio::ip::tcp protocol, std::uint16_t port, Server::Server(boost::asio::ip::tcp protocol, std::uint16_t port,
const fs::path& doc_root) const fs::path& doc_root)
: protocol_(protocol), : protocol_(protocol),
@ -27,6 +38,10 @@ Server::Server(boost::asio::ip::tcp protocol, std::uint16_t port,
void Server::Run(std::size_t workers, std::size_t loops) { void Server::Run(std::size_t workers, std::size_t loops) {
assert(workers > 0); assert(workers > 0);
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("Run(workers:%u, loops:%u)", workers, loops);
#endif
{ {
std::lock_guard<std::mutex> lock{ state_mutex_ }; std::lock_guard<std::mutex> lock{ state_mutex_ };
@ -151,8 +166,16 @@ bool Server::Listen(std::uint16_t port) {
} }
void Server::AsyncAccept() { void Server::AsyncAccept() {
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("AsyncAccept");
#endif
acceptor_.async_accept( acceptor_.async_accept(
[this](boost::system::error_code ec, tcp::socket socket) { [this](boost::system::error_code ec, tcp::socket socket) {
#if WEBCC_STUDY_SERVER_THREADING
LOG_USER("Accept handler");
#endif
// Check whether the server was stopped by a signal before this // Check whether the server was stopped by a signal before this
// completion handler had a chance to run. // completion handler had a chance to run.
if (!acceptor_.is_open()) { if (!acceptor_.is_open()) {
@ -162,8 +185,6 @@ void Server::AsyncAccept() {
if (!ec) { if (!ec) {
LOG_INFO("Accepted a connection"); LOG_INFO("Accepted a connection");
using namespace std::placeholders;
auto view_matcher = std::bind(&Server::MatchViewOrStatic, this, _1, auto view_matcher = std::bind(&Server::MatchViewOrStatic, this, _1,
_2, _3); _2, _3);

Loading…
Cancel
Save